I ran into a challenge while building my custom login page using Next Auth. The issue arises when I try to handle incorrect login data. If the login credentials are correct, I am able to successfully send JWT and redirect to /dashboard
. However, when the login data is incorrect, returning an error message to the login page proves to be tricky. Even though the error property changes, the response status remains as 200, indicating no error.
I currently rely on the error
property to display the error message:
Login Page:
const Login = () => {
const router = useRouter();
const [loginError, setLoginError] = useState();
const handleLogin = async (e) => {
e.preventDefault();
const login = e.target[0].value;
const password = e.target[1].value;
if (login.length && password.length) {
const res = await signIn("credentials", {
login,
password,
redirect: false,
});
if (res.error) setLoginError(true);
if (!res.error) router.push("/dashboard");
}
};
return (
<div className={styles.login}>
<form onSubmit={handleLogin} className={styles.form}>
<h2 className={styles.header}>Login</h2>
<input
type="text"
placeholder="Login"
className={styles.input}
/>
<input
type="password"
placeholder="Password"
className={styles.input}
/>
<button className={styles.button}>Log in</button>
</form>
{loginError && <div>ERROR</div>}
</div>
);
};
export default Login;
Route:
export const authOptions = {
providers: [
CredentialsProvider({
id: "credentials",
type: "credentials",
credentials: {
login: {
label: "login",
type: "text",
},
password: { label: "Password", type: "password" },
},
async authorize(credentials) {
try {
await connect();
const user = await User.findOne({
login: credentials.login,
});
if (!user) return null;
const isPasswordValid = await bcrypt.compare(
credentials?.password,
user?.password
);
if (isPasswordValid) {
const { password, _id: id, ...userRest } = user?._doc;
const userWithoutPassword = { id, ...userRest };
const accessToken = signJwtAccessToken({
userWithoutPassword,
});
return { ...userWithoutPassword, accessToken };
} else {
return null;
}
} catch (error) {
return new NextResponse("Database Error", { status: 500 });
}
},
}),
],
callbacks: {
async jwt({ token, user }) {
return { ...token, ...user };
},
async session({ session, token }) {
session.user = token;
session.accessToken = token.accessToken;
return session;
},
},
pages: {
signIn: "/login",
},
};
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
Would returning {status: 401, ok: false}
be a better approach? This is something to consider for handling errors in the login process.