How to Get User ID from Session in NextAuth (with or without JWTs)
Suppose we’re using NextAuth for user authentication in our Next.js application.
How can we obtain a user’s database ID from the session object?
The session object does not seem to include an ID.
{
user: {
name: 'John Travolta',
email: 'johntravolta@gmail.com',
image: null
},
expires: '2022-03-19T17:21:46.638Z'
}
The code snippets in this article require NextAuth.js v4. Check out how to upgrade to version 4.
Callbacks in NextAuth
In our NextAuth configuration found in [...nextauth].js
, we’ll notice a callbacks
field, where we can specify asynchronous functions that will be triggered by some event.
...
callbacks: {
async signIn({ user, account, profile, email, credentials }) {
return true;
},
async redirect({ url, baseUrl }) {
return baseUrl;
},
async session({ session, user, token }) {
return session;
},
async jwt({ token, user, account, profile, isNewUser }) {
return token;
}
...
For instance, when a user logs in using the signIn()
function, the signIn()
callback above will be triggered.
When a user is redirected to a callback URL on signin or signout, the redirect()
callback is triggered.
Similarly, calling getSession()
and useSession()
will invoke the session()
callback.
If we’re not persisting sessions in a database, getSession()
and useSession()
will invoke the jwt()
callback first, then the session()
callback.
Read up on callbacks in the NextAuth documentation.
Get user ID from session with JWT
Suppose we’re using JSON Web Token (JWT) sessions.
session: { strategy: "jwt", ... }
Access user ID using token.sub
We can access the user ID from the token
.
{
name: 'John Travolta',
email: 'johntravolta@gmail.com',
picture: null,
sub: 'pwoekfldksfpww10',
iat: 1645118504,
exp: 1647710504,
jti: '1we1rwe1-123e-w1e1-fdgd-fjru389r84ug'
}
We’ll notice that token.sub
contains the desired user ID.
iat
contains the timestamp of the JWT creation.exp
contains the token expiration timestamp. Timestamps are in seconds since epoch.sub
contains the unique identifier of the user.
Knowing that, we can forward that data into our session.
async session({ session, token }) {
if (session?.user) {
session.user.id = token.sub;
}
return session;
}
Access user ID using user
Another way to approach this problem is to pass the user.id
through the jwt()
callback.
async session({ session, token }) {
if (session?.user) {
session.user.id = token.uid;
}
return session;
},
async jwt({ token, user }) {
if (user) {
token.uid = user.id;
}
return token;
}
Get user ID from session without JWT
What if we’re persisting sessions in our database?
session: { strategy: "database", ... }
In this case, we can access the user
object for the ID.
{
id: 'pwoekfldksfpww10',
name: 'John Travolta',
email: 'johntravolta@gmail.com',
emailVerified: 2022-03-10T17:18:34.831Z,
image: null,
... // All other fields on the User model
}
user
is simply the User
object stored in the database. Naturally, the ID will be found in the id
field.
async session({ session, user }) {
if (session?.user) {
session.user.id = user.id;
}
return session;
}
Using new session from callback
Now, we want to obtain this user ID on the client.
const { data: session, status } = useSession();
if (session?.user) {
console.log(session.user.id);
}
If we’re using TypeScript, we’ll likely have to extend the session interface to include our new field.
The returned session object is of type Session
, which can be seen here.
export interface Session extends DefaultSession {}
export interface DefaultSession {
user?: {
name?: string | null;
email?: string | null;
image?: string | null;
};
expires: ISODateString;
}
We can extend this interface and override the user
field to include id
.
First, let’s create a file types/next-auth.d.ts
in our Next.js project.
Then, we can create new interfaces for Session
and JWT
(if appropriate).
import NextAuth, { DefaultSession } from "next-auth";
declare module 'next-auth' {
interface Session {
user?: {
id: string;
} & DefaultSession["user"];
}
}
// If we're using JWTs with the `uid` field
declare module 'next-auth/jwt/types' {
interface JWT {
uid: string;
}
}
Read up on extending default interface properties in NextAuth.