OiO.lk Community platform!

Oio.lk is an excellent forum for developers, providing a wide range of resources, discussions, and support for those in the developer community. Join oio.lk today to connect with like-minded professionals, share insights, and stay updated on the latest trends and technologies in the development field.
  You need to log in or register to access the solved answers to this problem.
  • You have reached the maximum number of guest views allowed
  • Please register below to remove this limitation

Next-auth signIn return {error:'Configuration'} in responce for invalid credentials. Next JS 14.2.3, Next-auth 5.0.0 Beta

  • Thread starter Thread starter Mehrwarz
  • Start date Start date
M

Mehrwarz

Guest
I just started to learn Next JS. I started with Next Js version 14.2.3 and I want to create a login form. I am using next-auth 5.0.0 beta for authentication. I am able to login in with correct credentials. But i want to return a message for user when the credentials are not matching. I am getting the object {error: 'configuration', status: 200, Ok...} and I have this line in the server console:

Code:
[auth][error] CallbackRouteError: Read more at https://errors.authjs.dev#callbackrouteerror
[auth][cause]: Error: Missing credentials.
    at Object.authorize (webpack-internal:///(rsc)/./src/util/AuthOptions.ts:44:27)

....

Here is my codes:

API Route

Code:
 // src/app/api/auth/[...nextauth]/route.ts
 export { GET, POST} from "@/util/AuthOptions";

Auth option file:

Code:
    // src/util/AuthOptions.ts
import User from "@/app/models/User";
import bcrypt from "bcrypt";
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";

const validateEmail = (email: string): boolean => {
const emailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|("."))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return emailRegex.test(String(email).toLowerCase());
};

interface Credentials {
username: string;
password: string;
}

const authOptions = {
// Configure one or more authentication providers
providers: [
    CredentialsProvider({
    // The credentials provider is used to generate a session
    credentials: {
        username: { label: "Username", type: "text" },
        password: { label: "Password", type: "password" },
    },

    async authorize(credentials: Credentials) {
        const { username, password } = credentials;

        if (!validateEmail(username)) {
        throw new Error("Invalid email format.");
        }

        if (!username || !password) {
        throw new Error("Missing credentials.");
        }

        const user = new User();
        const foundUser = await user.getFirst({ username });

        if (foundUser && (await bcrypt.compare(password, foundUser.password))) {
        return { id: foundUser.id, username: foundUser.username };
        } else {
        throw new Error("Invalid credentials.");
        }
    },
    }),
],

// JWT configuration for session management
jwt: {
    secret: process.env.NEXTAUTH_SECRET,
    maxAge: 30 * 24 * 60 * 60, // 30 days
},

// Callbacks for customizing JWT and session objects
callbacks: {
    async jwt({ token, user }) {
    if (user) {
        token.user = { id: user.id, username: user.username };
    }
    return token;
    },
    async session({ session, token }) {
    session.user = token.user;
    return session;
    },
},

// Enable debug mode in development environment
debug: process.env.NODE_ENV === "development",

// Set session storage using JWT
session: { jwt: true },

// Define custom pages for authentication flows
pages: {
    signIn: "/auth/login",
    signOut: "/auth/signout",
    error: "/auth/login",
},

// Database connection string (if applicable)
database: process.env.Database_URL,
};

export const { handlers:{GET,POST}, signIn, signOut, auth } = NextAuth(authOptions);

Login form

Code:
"use client";
import { getCsrfToken, signIn } from "next-auth/react";
import { useState, useEffect } from "react";

function LoginForm() {
  const [csrfToken, setCsrfToken] = useState("");
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState(null); 

  const handleSubmit = async (e) => {
    e.preventDefault();

    setError(null); // Clear error on submit

    if (!username) {
      setError("Username is required");
      return;
    }

    // if (!password) {
    //   setError("Password is required");
    //   return;
    // }

    const res = await signIn("credentials", {
      redirect: false,
      username,
      password,
      csrfToken,
    });

    if (res.error) {
      setError(res.error);
    }
  };

  useEffect(() => {
    const fetchToken = async () => {
      const token = await getCsrfToken();
      setCsrfToken(token);
    };
    fetchToken();
  }, []);

  return (
    <form onSubmit={handleSubmit} method="post">
      <div data-mdb-input-init className="form-outline mb-4">
        <input type="hidden" name="csrfToken" value={csrfToken} />
        <input
          type="email"
          id="username"
          className="form-control"
          name="username"
          value={username}
          onChange={(e) => setUsername(e.target.value)}
          aria-label="Username"
        />
        <label className="form-label" htmlFor="username">Email address</label>
      </div>

      <div data-mdb-input-init className="form-outline mb-4">
        <input
          type="password"
          id="password"
          className="form-control"
          placeholder="Keep it blank"
          name="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          aria-label="Password" 
        />
        <label className="form-label" htmlFor="password">Password</label>
      </div>

      {error && <p className="text-bg-danger">{error}</p>}
      <div className="form-check d-flex justify-content-center mb-4">
        <input
          className="form-check-input me-2"
          type="checkbox"
          id="keepLogin"
          name="keepLogin"
        />
        <label className="form-check-label" htmlFor="keepLogin">Remember me</label>
      </div>

      <button type="submit" className="btn btn-primary btn-block mb-4">Login</button>
    </form>
  );
}

export default LoginForm;

Thank for any instructions in advance.

<p>I just started to learn Next JS. I started with Next Js version 14.2.3 and I want to create a login form. I am using next-auth 5.0.0 beta for authentication. I am able to login in with correct credentials. But i want to return a message for user when the credentials are not matching.
I am getting the object {error: 'configuration', status: 200, Ok...} and I have this line in the server console:</p>
<pre><code>[auth][error] CallbackRouteError: Read more at https://errors.authjs.dev#callbackrouteerror
[auth][cause]: Error: Missing credentials.
at Object.authorize (webpack-internal:///(rsc)/./src/util/AuthOptions.ts:44:27)
</code></pre>
<p>....</p>
<p>Here is my codes:</p>
<p>API Route</p>
<pre><code> // src/app/api/auth/[...nextauth]/route.ts
export { GET, POST} from "@/util/AuthOptions";
</code></pre>
<p>Auth option file:</p>
<pre><code> // src/util/AuthOptions.ts
import User from "@/app/models/User";
import bcrypt from "bcrypt";
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";

const validateEmail = (email: string): boolean => {
const emailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|("."))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return emailRegex.test(String(email).toLowerCase());
};

interface Credentials {
username: string;
password: string;
}

const authOptions = {
// Configure one or more authentication providers
providers: [
CredentialsProvider({
// The credentials provider is used to generate a session
credentials: {
username: { label: "Username", type: "text" },
password: { label: "Password", type: "password" },
},

async authorize(credentials: Credentials) {
const { username, password } = credentials;

if (!validateEmail(username)) {
throw new Error("Invalid email format.");
}

if (!username || !password) {
throw new Error("Missing credentials.");
}

const user = new User();
const foundUser = await user.getFirst({ username });

if (foundUser && (await bcrypt.compare(password, foundUser.password))) {
return { id: foundUser.id, username: foundUser.username };
} else {
throw new Error("Invalid credentials.");
}
},
}),
],

// JWT configuration for session management
jwt: {
secret: process.env.NEXTAUTH_SECRET,
maxAge: 30 * 24 * 60 * 60, // 30 days
},

// Callbacks for customizing JWT and session objects
callbacks: {
async jwt({ token, user }) {
if (user) {
token.user = { id: user.id, username: user.username };
}
return token;
},
async session({ session, token }) {
session.user = token.user;
return session;
},
},

// Enable debug mode in development environment
debug: process.env.NODE_ENV === "development",

// Set session storage using JWT
session: { jwt: true },

// Define custom pages for authentication flows
pages: {
signIn: "/auth/login",
signOut: "/auth/signout",
error: "/auth/login",
},

// Database connection string (if applicable)
database: process.env.Database_URL,
};

export const { handlers:{GET,POST}, signIn, signOut, auth } = NextAuth(authOptions);
</code></pre>
<p>Login form</p>
<pre><code>"use client";
import { getCsrfToken, signIn } from "next-auth/react";
import { useState, useEffect } from "react";

function LoginForm() {
const [csrfToken, setCsrfToken] = useState("");
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState(null);

const handleSubmit = async (e) => {
e.preventDefault();

setError(null); // Clear error on submit

if (!username) {
setError("Username is required");
return;
}

// if (!password) {
// setError("Password is required");
// return;
// }

const res = await signIn("credentials", {
redirect: false,
username,
password,
csrfToken,
});

if (res.error) {
setError(res.error);
}
};

useEffect(() => {
const fetchToken = async () => {
const token = await getCsrfToken();
setCsrfToken(token);
};
fetchToken();
}, []);

return (
<form onSubmit={handleSubmit} method="post">
<div data-mdb-input-init className="form-outline mb-4">
<input type="hidden" name="csrfToken" value={csrfToken} />
<input
type="email"
id="username"
className="form-control"
name="username"
value={username}
onChange={(e) => setUsername(e.target.value)}
aria-label="Username"
/>
<label className="form-label" htmlFor="username">Email address</label>
</div>

<div data-mdb-input-init className="form-outline mb-4">
<input
type="password"
id="password"
className="form-control"
placeholder="Keep it blank"
name="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
aria-label="Password"
/>
<label className="form-label" htmlFor="password">Password</label>
</div>

{error && <p className="text-bg-danger">{error}</p>}
<div className="form-check d-flex justify-content-center mb-4">
<input
className="form-check-input me-2"
type="checkbox"
id="keepLogin"
name="keepLogin"
/>
<label className="form-check-label" htmlFor="keepLogin">Remember me</label>
</div>

<button type="submit" className="btn btn-primary btn-block mb-4">Login</button>
</form>
);
}

export default LoginForm;
</code></pre>
<p>Thank for any instructions in advance.</p>
 
Top