I also have the same issue working with next-auth and there is no sufficient material available for this
I built two types of auth systems in my solution I came up with:
This file is app/api/auth/[...nextauth]/route.js
import NextAuth from 'next-auth';
import GoogleProvider from 'next-auth/providers/google';
import {authenticate} from "@/app/(auth)/login/action";
import CredentialsProvider from "next-auth/providers/credentials"
export const authOptions = {
providers: [
CredentialsProvider({
type: "credentials",
credentials: {
username: {label: "UserName", type: "text", placeholder: "Enter your username"},
email: {label: "Email", type: "email", placeholder: "Enter your email"},
password: {label: "Password", type: "password"},
},
async authorize(credentials, req) {
const {username, email, password} = credentials;
const user = {
name: username ?? '',
email: email,
password: password,
};
const data = await authenticate(user)
if (data.status === 200) {
return {
username: data.data.user.name,
email: data.data.user.email,
token: data.data.token,
role: data.data.user.role,
};
}
return null;
},
}),
GoogleProvider({
clientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID,
clientSecret: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_SECRET,
}),
],
callbacks: {
async session({session, token}) {
let data = null;
if (token && token.id !== undefined) {
//Setting user if logged in by google
const user = {
google_id: token.id,
name: token.name,
email: token.email,
image: token.image,
}
data = await authenticate(user);
}
if (token) {
session.user = token;
if (data !== null) {
session.user.role = data.data.user.role;
session.user.token = data.data.token;
}
session.user.isLoggedIn = true;
return session;
}
return session;
},
async jwt({token, user}) {
return {...token, ...user}
},
},
secret: process.env.NEXTAUTH_SECRET_KEY,
jwt: {
secret: process.env.NEXTAUTH_SECRET_KEY,
encryption: true,
maxAge: 5 * 60,
},
pages: {
signIn: [
'/login'
],
error: '/register'
},
debug: true
};
const handler = NextAuth(authOptions);
export {handler as GET, handler as POST}
In this when the authorize function runs it sends the user object to jwt and jwt sends it to the session to store it
In the case of Google I am checking if the token id exists in my case, the token id is Google ID i.e. if I logged in with Google then id variable is used as a password.
and data = await authenticate(user) is a custom function used to authenticate the user.
Resource: https://next-auth.js.org/providers/credentials
If u find any thing in this description incorrect or is there's any better way to do this please let me know.