I have a private next project with Next Auth and I am implementing credentials only email and password because these users will be created at the Firebase Auth panel. My Next Auth seems like this:
import NextAuth from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
import { auth, app } from '@/util/firebase';
import { signInWithEmailAndPassword } from 'firebase/auth';
export default NextAuth({
secret: process.env.NEXTAUTH_SECRET,
pages: {
signIn: '/auth/signin',
},
providers: [
CredentialsProvider({
name: 'Credentials',
credentials: {
email: { label: 'Email', type: 'email' },
password: { label: 'Password', type: 'password' },
},
async authorize(credentials, req) {
try {
const userCredential = await signInWithEmailAndPassword(
auth,
credentials.email,
credentials.password
);
// I want to get this token and save as Bearer Authorization token userCredential.idToken
if (userCredential.user) return { email: userCredential.user.email };
else return null;
} catch (error) {
throw new Error('Invalid email or password');
}
},
}),
],
});
But there is a little problem. For the requests API, I need to send a valid Bearer token. How can I store and retrieve the token?
Observation: Token is available in userCredential.idToken
The purpose of next-auth is to store the user data in a protected session
So first you have to return from the authorize
method what you want to store in you session :
async authorize(credentials, req) {
//...
if (userCredential) {
return {
email: userCredential.user.email,
accessToken: userCredential.idToken
//... any other keys you want to include in the returned object
}
}
else return null;
} catch (error) {
throw new Error("Invalid email or password");
}
}
Next you need to store these data in your session, to do so, you have to use callbacks :
JWT callback
This callback is called whenever a JSON Web Token is created (i.e. at sign in) or updated (i.e whenever a session is accessed in the client). The returned value will be encrypted, and it is stored in a cookie.
Session callback
The session callback is called whenever a session is checked. By default, only a subset of the token is returned for increased security. If you want to make something available you added to the token (like access_token and user.id from above) via the jwt() callback, you have to explicitly forward it here to make it available to the client.
Likely, the object returned by the authorize
method is available as parameter named user
in the jwt callback, so you get advantage of this latter to update the token and return it
Then the object returned by the jwt callback is available in the session callback as parameter named token
so again you use this token to update the session
callbacks: {
async jwt({ user, token }) {
// update token if user is returned
if (user) {
token.email = user.email;
token.accessToken= user.accessToken;
}
// return final_token
return token;
},
async session({ session, token}) {
// update session from token
session.email = token.email;
session.accessToken= token.accessToken;
return session;
},
},
You now have your session including the information you wanted to store.
So from the client side you can access it using useSession()
import { useSession } from "next-auth/react";
const Home = () => {
const session = useSession();
const myAccessToken = session.data.accessToken;
//...
}
See also getServerSession()