How to get Next-Auth session to include custom properties

I'm working on an app which uses the Next-Auth credentials provider - I'm running into a few related problems when it comes to adding some of my data into the session object and token. I want to add in the username, role, id and profile image of a user to the session and token, and after adding an interface for session, JWT and user in my types definition I have managed to get the token including such fields, but session only has the original default properties in the session object - perhaps related to this, when I useSession and log it on a client-side component I see all my session object as it should be, but reloading the page then gets rid of it (I'm guessing due to the session issue). Below is my callbacks and types definition for next-auth - I've look around a lot triyng to figure this out and keep running into more problems, so any help figuring this out would be greatly appreciated!
callbacks: {
async jwt({ token, user }) {
if (user) {
token.username = user.username;
token.profileImage = user.profileImage;
token.role = user.role;
token.id = user.id;
}
return token;
},
async session({ session, token }) {
console.log({ session, token })

if (token) {
session.user.username = token.username;
session.user.profileImage = token.profileImage;
session.user.role = token.role;
session.user.id = token.id;
return session
}
}
callbacks: {
async jwt({ token, user }) {
if (user) {
token.username = user.username;
token.profileImage = user.profileImage;
token.role = user.role;
token.id = user.id;
}
return token;
},
async session({ session, token }) {
console.log({ session, token })

if (token) {
session.user.username = token.username;
session.user.profileImage = token.profileImage;
session.user.role = token.role;
session.user.id = token.id;
return session
}
}
declare module "next-auth/jwt" {
interface JWT {
id: string
role?: string
username?: string
profileImage?: string
}
}

declare module "next-auth" {
interface Session {
user?: {
id: string;
role: string;
profileImage: string;
username: string;
} & DefaultSession["user"];
}

interface User {
id: string;
role: string;
profileImage: string;
username: string;
}
}
declare module "next-auth/jwt" {
interface JWT {
id: string
role?: string
username?: string
profileImage?: string
}
}

declare module "next-auth" {
interface Session {
user?: {
id: string;
role: string;
profileImage: string;
username: string;
} & DefaultSession["user"];
}

interface User {
id: string;
role: string;
profileImage: string;
username: string;
}
}
7 Replies
Alan Ibarra-2310
Alan Ibarra-2310•12mo ago
It looks like you're conditionally returning back your session. From what I have seen the session needs to be returned regardless and you alter the session if the token exist. This is the repo from where I got the next auth working. https://github.com/shadcn/taxonomy/blob/main/lib/auth.ts
GitHub
taxonomy/auth.ts at main · shadcn/taxonomy
An open source application built using the new router, server components and everything new in Next.js 13. - taxonomy/auth.ts at main · shadcn/taxonomy
admiralackbar411
admiralackbar411•12mo ago
I tried that repo and I still can't seem to get it to work - I have done a bit of logging and it's confusing me a bit now in terms of what I am getting in response, using that repo I don't seem to be able to get any of my extended data to show up, other than in some logging, but it doesn't get returned at all.
callbacks: {
async session({ token, session }) {
console.log(`Session: ${JSON.stringify(session)}`)
if (token) {
session.user.username = token.username;
session.user.profileImage = token.profileImage;
session.user.role = token.role;
session.user.id = token.id;
console.log(`TokenSession: ${JSON.stringify(session)}`)
}
return session;
},
async jwt({ token, user }) {
const dbUser = await prisma.user.findFirst({
where: {
email: token.email,
}
})

if (!dbUser) {
if (user) {
token.id = user?.id;
token.role = user?.role;
token.username = user?.username;
token.profileImage = user?.profileImage;
token.email = user?.email;
console.log(`UserTokenCheck: ${JSON.stringify(token)}`)
}

console.log(`NoDbUserToken: ${JSON.stringify(token)}`)
return token
}

console.log(`token: ${JSON.stringify(token)}`)
console.log(`user: ${JSON.stringify(dbUser)}`)

return token
}
}
callbacks: {
async session({ token, session }) {
console.log(`Session: ${JSON.stringify(session)}`)
if (token) {
session.user.username = token.username;
session.user.profileImage = token.profileImage;
session.user.role = token.role;
session.user.id = token.id;
console.log(`TokenSession: ${JSON.stringify(session)}`)
}
return session;
},
async jwt({ token, user }) {
const dbUser = await prisma.user.findFirst({
where: {
email: token.email,
}
})

if (!dbUser) {
if (user) {
token.id = user?.id;
token.role = user?.role;
token.username = user?.username;
token.profileImage = user?.profileImage;
token.email = user?.email;
console.log(`UserTokenCheck: ${JSON.stringify(token)}`)
}

console.log(`NoDbUserToken: ${JSON.stringify(token)}`)
return token
}

console.log(`token: ${JSON.stringify(token)}`)
console.log(`user: ${JSON.stringify(dbUser)}`)

return token
}
}
This is what the above returns
{ user: { name: null, email: 'test@test.com', image: undefined } }
token: {"name":null,"email":"test@test.com","sub":"5","iat":1686223502,"exp":1688815502,"jti":"6394f114-c749-4e95-801e-a95c15cdb146"}
user: {"id":5,"username":"test","email":"test@test.com","password":"$2b$10$dbd/bBJ3VGUVVN8H494L1uoZImkGi1yiIzktpADHkSyffuLRAvcgq","name":null,"profileImage":null,"createdAt":"2023-06-08T11:24:44.708Z","updatedAt":"2023-06-08T11:24:44.708Z","role":"MEMBER"}
Session: {"user":{"name":null,"email":"test@test.com"},"expires":"2023-07-08T11:25:24.609Z"}
TokenSession: {"user":{"name":null,"email":"test@test.com"},"expires":"2023-07-08T11:25:24.609Z"}
token: {"name":null,"email":"test@test.com","sub":"5","iat":1686223524,"exp":1688815524,"jti":"1f883b4f-cd36-4a3e-bc77-9457a137b247"}
user: {"id":5,"username":"test","email":"test@test.com","password":"$2b$10$dbd/bBJ3VGUVVN8H494L1uoZImkGi1yiIzktpADHkSyffuLRAvcgq","name":null,"profileImage":null,"createdAt":"2023-06-08T11:24:44.708Z","updatedAt":"2023-06-08T11:24:44.708Z","role":"MEMBER"}
Session: {"user":{"name":null,"email":"test@test.com"},"expires":"2023-07-08T11:25:24.894Z"}
TokenSession: {"user":{"name":null,"email":"test@test.com"},"expires":"2023-07-08T11:25:24.894Z"}
{ user: { name: null, email: 'test@test.com', image: undefined } }
token: {"name":null,"email":"test@test.com","sub":"5","iat":1686223502,"exp":1688815502,"jti":"6394f114-c749-4e95-801e-a95c15cdb146"}
user: {"id":5,"username":"test","email":"test@test.com","password":"$2b$10$dbd/bBJ3VGUVVN8H494L1uoZImkGi1yiIzktpADHkSyffuLRAvcgq","name":null,"profileImage":null,"createdAt":"2023-06-08T11:24:44.708Z","updatedAt":"2023-06-08T11:24:44.708Z","role":"MEMBER"}
Session: {"user":{"name":null,"email":"test@test.com"},"expires":"2023-07-08T11:25:24.609Z"}
TokenSession: {"user":{"name":null,"email":"test@test.com"},"expires":"2023-07-08T11:25:24.609Z"}
token: {"name":null,"email":"test@test.com","sub":"5","iat":1686223524,"exp":1688815524,"jti":"1f883b4f-cd36-4a3e-bc77-9457a137b247"}
user: {"id":5,"username":"test","email":"test@test.com","password":"$2b$10$dbd/bBJ3VGUVVN8H494L1uoZImkGi1yiIzktpADHkSyffuLRAvcgq","name":null,"profileImage":null,"createdAt":"2023-06-08T11:24:44.708Z","updatedAt":"2023-06-08T11:24:44.708Z","role":"MEMBER"}
Session: {"user":{"name":null,"email":"test@test.com"},"expires":"2023-07-08T11:25:24.894Z"}
TokenSession: {"user":{"name":null,"email":"test@test.com"},"expires":"2023-07-08T11:25:24.894Z"}
Alan Ibarra-2310
Alan Ibarra-2310•12mo ago
Ok, this is what was first outputted when I signed in with Github. I added a console.log for the user because for some reason it was finding a user even though there wasn't any in the DB. So, I switched the Prisma query to findUnique and it didn't find a user thats why you see the value of null. I also added some default values to properties like role, username because I don't have those values in my DB.
Alan Ibarra-2310
Alan Ibarra-2310•12mo ago
I guess the session callback gets created when you use getServerSession function or some other way I'm using it within a server component. Anyways, it seems the JWT callback gets called again, but the user is undefined because UserTokenCheck does not get logged but the NoDbUserToken does. And again, the user is null. The last part is a console.log of the session in a server component.
Alan Ibarra-2310
Alan Ibarra-2310•12mo ago
This is my server component and the function I use to get the session.
Alan Ibarra-2310
Alan Ibarra-2310•12mo ago
Lastly, this is next auth api setup
admiralackbar411
admiralackbar411•12mo ago
Thank you! This works, and I am getting the correct data back now! 🙂 😄
Want results from more Discord servers?
Add your server
More Posts