I want to store my user’s id
and role
in my nextAuth session, should I perform a lookup in my database for the user during the authOptions.callbacks
?
The consensus I’ve found on Github discussions and in the Docs, is to pass information from the callback.jwt(token)
into the callback.session(token)
. The problem is, when I use Google or Github OAuth providers, they only provide a jwt(token)
argument with the fields: name, email, picture, sub, iat, exp, jti
and the rest of the args (user
, account
, profile
) values provided in the jwt callback are undefined
.
since none of those provided args have the fields I need, should I use the returned unique email
in my jwt token to perform a database lookup within callback.jwt(), append the returned mongodb document’s id and role to the token, and then append those to the following session return value?
// [...nextAuth].ts authOptions
...
session: {
strategy: "jwt",
},
callbacks: {
async jwt({ token, user, account, profile }) {
// user, account, and profile are undefined when using OAuth
// token returns { user: "a", email: "b", image: "c" }
// should I perform a database lookup here, find the matching user via email
// and then append the found user.id and user.role into token?
return token;
},
async session({ session, user, token }) {
// then insert those id and role key/values into session here before returning?
return session;
},
},
Is performing a database lookup within my authOptions.callback a good idea? –is this convention?
Extra – why doesn’t nextAuth lookup the user by matching email automatically?
— Resolved
Since I am using MongoDB as my database, I have the MongoDB adapter setup. I was originally thinking that the adapter would perform lookups for the matching user via email in my database when signing in through OAuth and then surface the matching user in my callback.jwt(user)
argument. Yet, my user argument is undefined
when using OAuth but exists when using Credentials. I am a further confused by the intellisense message when hovering over callback.jwt(user)
as it seems to indicate something contradictory?
// intellisense for callback.jwt(user)
Either the result of the OAuthConfig.profile or the CredentialsConfig.authorize callback.
Should I expect .profile
to be my database user? Currently, it’s returning undefined
. Is my adapter not working correctly, is this behavior dependent on the underlying OAuth provider, or am I just misunderstanding/mis-implementing the feature?
2
Answers
I continued to tinker around with NextAuth and learned that there is a bit of a convention with all adapters. When you work with "Credentials" and/or an OAuth provider, your database user is in fact looked up and returned back. Within the the
jwt
callbackuser
will return as the result of the lookup for both provider types. Just make sure you wrap it with a conditional check as shown below.It's worth noting that this requires you to have a database set up, and just as NextAuth is able to create/update (automatically)
users
/accounts
, it can --and does, look up the matching collections/rows during signin and registration. Which means you do not have to perform another look-up within the jwt callback to get your user's information, since your database information is automatically handed back to you during signin through the callback flow.Also, while I have a database, as per the docs, you can override the default "database" strategy with
session: {strategy: 'jwt' }
which is required if you still want to sign in and register users in through email/password credentials..profile
is not your database user. its type:this comes from the oauth provider. you have to fetch the database user inside the
jwt
callback