skip to Main Content

I am creating my own login page in Next Auth and I have encountered a problem. After submitting the form, I check if the data is correct. If it is, I send JWT and redirect to /dashboard – it works as I would like. However, if the login data is incorrect I would like to return an error to my login page. However, when I return return null, the response status is 200, as if there is no error. Only the error property changes.

Currently, I base the return on the error and display the error based on it:

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="Hasło"
                        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 };

However, is this a good approach? Is it possible to return {status: 401, ok: false}?

2

Answers


  1. You are returning null in case the data is invalid. null !== Error. You need to throw error if the data is invalid.

    Something like this:

    try {
        await connect();
        const user = await User.findOne({
            login: credentials.login,
        });
        if (!user) throw new Error('Invalid credentials');
    
        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 {
            throw new Error('Invalid credentials');
        }
    } catch (error) {
        return new NextResponse("Database Error", { status: 500 });
    }
    
    Login or Signup to reply.
  2. It is a bug in NextAuth but there is a workaround.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search