I’m working on a Next.js application with authentication handled by a separate Node.js API deployed on Heroku. My goal is to use NextAuth.js for managing user sessions in the frontend, where the backend API handles login and returns a JWT token. However, I’m encountering issues during the login process using NextAuth.js with my custom credentials provider.
When I attempt to log in, I am unexpectedly redirected to http://localhost:3000/api/auth/error
, despite setting redirect: false
in my signIn
method. Additionally, I am not able to successfully log in.
Upon investigation, when I checked my API logs, it did not show that any request was made to the login route for some reason. This happens even after replacing the environment variable name with the actual route name.
Below is my folder structure:
Here’s the expected response from my API upon successful login:
{
"user": {
"location": {
"city": "Bradford, UK",
"lat": 53.7937996,
"lng": -1.7563583
},
"_id": "659f77b9eaee64fce34d9083",
"fullName": "opeyemi david odedeyi",
"email": "[email protected]",
"gender": "prefer not to say",
"isEmailConfirmed": false,
"isActive": true,
"createdAt": "2024-01-11T05:08:09.359Z",
"updatedAt": "2024-01-13T04:35:40.948Z",
"uniqueURL": "opeyemi-david-odedeyi-1704949689359",
"__v": 3
},
"token": "<JWT_TOKEN>",
"message": "User logged in successfully"
}
Below is the code for my login page in the Next.js app:
import { useState } from 'react';
import { signIn } from 'next-auth/react';
export default function Login() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const buttonClicked = async (e) => {
e.preventDefault();
const result = await signIn('credentials', {
redirect: false,
email,
password
});
if (result.error) {
console.log(result.error);
} else {
console.log(result);
}
};
// ... JSX for form inputs ...
return (
// ... JSX for the login form ...
);
}
And here is my [...nextauth].js
configuration:
import NextAuth from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
export default NextAuth({
providers: [
CredentialsProvider({
name: 'credentials',
authorize: async (credentials) => {
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/login`, {
method: 'POST',
body: JSON.stringify(credentials),
headers: { "Content-Type": "application/json" }
});
const user = await res.json();
if (!res.ok) {
throw new Error(user.message || "Something Went wrong!!");
}
return user;
}
})
],
callbacks: {
jwt: async ({ token, user }) => {
if (user) {
token.accessToken = user.token;
}
return token;
},
session: async ({ session, token }) => {
session.accessToken = token.accessToken;
return session;
}
},
});
I’m not sure why I’m being redirected to the error page and why the login isn’t successful, and why is no request made to my login route via the api logs. Is there something I’m missing in my NextAuth.js setup or the way I’m handling the login process? Any insights or suggestions would be greatly appreciated.
2
Answers
I was able to solve the problem.
The short answer is that the routing method i used is still in beta and it is slowly getting supported. not-planned-features, and below is the part you need to pay attention to:
The problem was with the routing but it is much more complicated than that. as at of today, the support for src routing for example
src/app/api/auth/[...nextauth].js
is not there yet. for now using the route fornext-auth
like thispages/api/auth/[...nextauth].js
is the easiest way.Basically, the solution was to use both the
pages
route andsrc
route. as said by this line on the same link:and here is how my folder structure looked like after to make it work:
this is how i was able to get it to work.
The code looks good to me.
Could you check the terminal to see if there’s any error from the Next.js app?
Also, add logs into authorize, and the callbacks to check if you receive exactly what you expect.
One side thing, which is not a problem, the NextAuth route runs in the server, so optionally you could you a non-client exposed environment variable instead of process.env.NEXT_PUBLIC_API_URL (just remove NEXT_PUBLIC to make it server-only).