Adding custom value to NextAuth session - [next-auth][error][JWT_SESSION_ERROR]

I am trying to add a username field to my NextAuth session data in my t3 app and am getting the following error: https://next-auth.js.org/errors#jwt_session_error Cannot read properties of undefined (reading 'username') I have added an optional username field to both my User and Session overrides like this:
declare module "next-auth" {
interface Session extends DefaultSession {
user: DefaultSession["user"] & {
id: string;
// ...other properties
username?: string;
// role: UserRole;
};
}

interface User extends DefaultUser {
username?: string;
// ...other properties
// role: UserRole;
}
}
declare module "next-auth" {
interface Session extends DefaultSession {
user: DefaultSession["user"] & {
id: string;
// ...other properties
username?: string;
// role: UserRole;
};
}

interface User extends DefaultUser {
username?: string;
// ...other properties
// role: UserRole;
}
}
And here are my session and jwt callbacks:
callbacks: {
session({ session, token, user }) {
return {
...session,
user: {
...session.user,
id: token.sub,
username: user.username,
},
};
},
jwt({ token, user }) {
console.log("USER: ", user);
return { ...token, user };
},
},
callbacks: {
session({ session, token, user }) {
return {
...session,
user: {
...session.user,
id: token.sub,
username: user.username,
},
};
},
jwt({ token, user }) {
console.log("USER: ", user);
return { ...token, user };
},
},
The strange part is the log in the jwt callback logs the correct user obejct (with the username) once, then logs undefined, and then logs the error above. Any idea why my user would be getting set to undefined and passed into the jwt callback? (logs below)
USER: {
id: ${userIdFromDb},
email: null,
image: null,
username: 'newuser'
}
USER: undefined
[next-auth][error][JWT_SESSION_ERROR]
USER: {
id: ${userIdFromDb},
email: null,
image: null,
username: 'newuser'
}
USER: undefined
[next-auth][error][JWT_SESSION_ERROR]
19 Replies
Josh
Josh6mo ago
ah your using jwts
Josh
Josh6mo ago
iirc there was some fuckery I had to do to get that to work right why are you using jwt vs db sessions?
tyler4949
tyler49496mo ago
Which seems to be exactly what I am running into. But their solution didnt seem to fix it for me I wanted to use middleware with nextauth and iirc you need jwt for that https://create.t3.gg/en/usage/next-auth#usage-with-nextjs-middleware
Josh
Josh6mo ago
ah yeah you can't ping the db iirc for some weird reason do you need something in the client jwt? or just that the user is logged in
tyler4949
tyler49496mo ago
So I found a "solution" to this, if I append the username to my jwt like this:
jwt({ token, user }) {
if (!!user) token.user = user;
return token;
},
jwt({ token, user }) {
if (!!user) token.user = user;
return token;
},
I can pull the username from token in the session() callback instead of the user (because its undefined). Is that the fuckery youre talking about? Because that feels gross lol idk why I cant just access the user Just auth state tbh. I was just following Theo's youtube video and wanted to add the middleware to stay in sync/learn. But I am more familiar with NextAuth than Clerk and use it in other projects so wanted to stay consistent
Josh
Josh6mo ago
ahhhh yep that's it ah okay hold on then if you only care if the user is logged in, just check if the nextauth cookie is present in their request technically, it's not 100000% secure, because it could be an outdated token, but the idea is you are optimistically assuming they are logged in, and when they actually get to a page that grabs the session, next auth will bounce them to the sign in page if you have it configured that way atleast you're middle ware runs every request so you want that to be as fast as possible and imo db states are just easier to use /manage I use this method in our products and it works like a charm
tyler4949
tyler49496mo ago
Yeah okay fair. Appreciate the input. At this point Im committed to solving this lol but if I change my mind I will try that approach
Josh
Josh6mo ago
word for your problem I'm 99% sure this was it for me cause I use jwt's during development and then swap to db sessions in prod
tyler4949
tyler49496mo ago
Yeah it looks like this is the answer in their github too: https://github.com/nextauthjs/next-auth/discussions/4117 Thats crazy lmao Wtf is the point of accepting the user in the callback if its undefined
Josh
Josh6mo ago
who knows lmao
tyler4949
tyler49496mo ago
btw, do you remember what you did about the types yelling at you? Since the User type isnt on the JWT, it freaks out lol
No description
tyler4949
tyler49496mo ago
If I do use this appraoch temporarily I dont want typesript yelling at me
Josh
Josh6mo ago
yeah I can find it
tyler4949
tyler49496mo ago
Beast thank you
Josh
Josh6mo ago
supposedly I'm doing this
session: ({ session, user, token }) => {
if (env.VERCEL_ENV === "preview" || env.VERCEL_ENV === "development")
return {
...session,
user: token.user as User,
};
return {
...session,
user: {
id: user.id,
handle: user.handle,
email: user.email,
avatar: user.avatar,
name: user.name,
},
};
},
session: ({ session, user, token }) => {
if (env.VERCEL_ENV === "preview" || env.VERCEL_ENV === "development")
return {
...session,
user: token.user as User,
};
return {
...session,
user: {
id: user.id,
handle: user.handle,
email: user.email,
avatar: user.avatar,
name: user.name,
},
};
},
tyler4949
tyler49496mo ago
Ahh just casting it, Im dumb idk why I didnt do that lmao thank you
Josh
Josh6mo ago
jwt:
env.VERCEL_ENV === "preview" || env.VERCEL_ENV === "development"
? async ({ token }) => {
const [user] = await db
.select()
.from(Users)
.where(eq(Users.email, token.email!));
const res = { ...token, user };
return res;
}
: undefined,
jwt:
env.VERCEL_ENV === "preview" || env.VERCEL_ENV === "development"
? async ({ token }) => {
const [user] = await db
.select()
.from(Users)
.where(eq(Users.email, token.email!));
const res = { ...token, user };
return res;
}
: undefined,
yur
tyler4949
tyler49496mo ago
In case you wanna bump the issue with me or share this in case someone asks in the future: https://github.com/nextauthjs/next-auth/discussions/9438. Seriously apprecaite your help @Josh