next-auth: Crendtials provider with redirect:false - next-auth/react signIn returns status:200 ok:true with failed authentication.
Provider type
Credentials
Environment
Using dockerised environment FROM node:18-alpine so
- node 18 latest,
- next 13.4.1
- next-auth 4.22.1
- react 18.2
Reproduction URL
https://github.com/OdifYltsaeb/next-auth-bug-report
Describe the issue
I’m following the most basic setup described here https://medium.com/@tom555my/strapi-next-js-email-password-authentication-a8207f72b446 and the next-auth/react signIn (see console.log('stuff in handlesubmit', stuff); in the code below) resolves into { error: "CredentialsSignin", status: 200, ok: true, url: null } when authentication fails due to incorrect email/password. The strapi request returns with error 400, and thus the error message in the object that singIn resolves to, but the status is 200, while it should probably be something else.
// app/api/auth/[…nextauth]/route.js
import NextAuth from 'next-auth';
import { authOptions } from '../../../../lib/auth';
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
// lib/auth.js
import CredentialsProvider from "next-auth/providers/credentials";
import axios from "../utils/axios";
const signIn = async function({ email, password }) {
const res = await axios.post(`${process.env.STRAPI_URL}/api/auth/local`, {
identifier: email,
password
});
return res;
};
const authOptions = {
session: {
strategy: "jwt"
},
providers: [
CredentialsProvider({
name: "Sign in with Email",
credentials: {
email: { label: "Email", type: "text" },
password: { label: "Password", type: "password" }
},
async authorize(credentials, req) {
if (credentials == null) return null;
try {
const { user, jwt } = await signIn({
email: credentials.email,
password: credentials.password
});
return { ...user, jwt };
} catch (error) {
console.log('FAIL!', Object.keys(error));
// Sign In Fail
return null;
}
}
})
],
callbacks: {
session: async ({ session, token }) => {
session.id = token.id;
session.jwt = token.jwt;
return Promise.resolve(session);
},
jwt: async ({ token, user }) => {
const isSignIn = user ? true : false;
if (isSignIn) {
token.id = user.id;
token.jwt = user.jwt;
}
return Promise.resolve(token);
}
}
};
export { authOptions, signIn };
// components/forms/LoginForm.js
...
import { signIn } from 'next-auth/react';
...
const LoginForm = withFormik({
mapPropsToValues: () => ({
email: '',
password: '',
}),
validationSchema: Yup.object().shape({
email: Yup.string().email('Invalid email address').required('Email is required'),
password: Yup.string().required('Password is required'),
}),
handleSubmit: async (values, { props, ...formik }) => {
await signIn('credentials', {
redirect: false,
email: values.email,
password: values.password,
}).then((stuff) => {
console.log('stuff in handlesubmit', stuff);
});
},
displayName: 'LoginForm', // helps with React DevTools
})(Login);
How to reproduce
- clone project, make sure you have docker + docker compose and make commands available
- use
make build-devto set stuff u p - use
make start-devto run docker compose - navigate to http://localhost:8000/login
- open console
- enter random email and password and observe the console printout.
Expected behavior
I would expect that the status is not OK and code is not 200.
About this issue
- Original URL
- State: closed
- Created a year ago
- Reactions: 16
- Comments: 22 (4 by maintainers)
I ran into the exact same issue. As far as I can tell, this is happening only under the
approuter.I fixed this issue with the following patch-package patch.
patches/next-auth+4.22.1.patch
You may also need to clear the
.nextfolder after installing the patch (rm -rf .next)Hey, Have you found a fix yet ? I’m running the same issue, I think I’m going insane
+1 same issue. I’m completely regretting of choosing nextauth as my auth library. It’s giving me headache after headache
Check lucia auth for alternative or just use clerk.
Been having this problem for few weeks, guess ill just wait the official fix.
I have managed to do a workaround by adding
throw new Error(""+res.status);inside authorize functionif(response.status !== 200)And then in my login page I haveSignIn("credentials", {email: values.email, password: values.password, redirect: false}).then((response:SignInRresponse | undefined) => { if(response?.error !== null) { if(response?.error === "401") form.setError("password", {message:"Incorrect password"}); } console.log(response ; });this works for me and doesn’t create empty session but throws an error on the form and doesn’t sign in. Hope it helps, can provide more code if needed.@igordanchenko I did it, but won’t work
Looks the same as #7725