9

I use NextAuth for signIn with discord provider and I need to add userID into the session object. For that I use session callback but user object is undefined. When I try to add userID to the session object, I got an error like this :

[next-auth][error][JWT_SESSION_ERROR] https://next-auth.js.org/errors#jwt_session_error Cannot read properties of undefined (reading 'id')

Indeed, it seems the user object is undefined but I don't have any solution.

export default NextAuth({
  providers: [
    DiscordProvider({
      clientId: process.env.DISCORD_CLIENT_ID,
      clientSecret: process.env.DISCORD_CLIENT_SECRET,
      authorization: { params: { scope: 'identify' } }
    })
  ],
  session: {
    jwt: true
  },
  jwt: {
    secret: process.env.JWT_SECRET
  },
  callbacks: {
    async session({session, user}) {
      session.user.id = user.id
      return session
    },
    async jwt(token) {
      return token
    }
  }
})
1
  • It's most likely complaining about session.user being undefined hence throwing the error when you try to access its id property. What if you do session.user = user instead? Commented May 1, 2022 at 18:42

8 Answers 8

6

You can do it like that

    providers: [ 
        Github({
            clientId: process.env.GITHUB_ID,
            clientSecret:process.env.GITHUB_SECRET,
        })
    ],
    database :process.env.DB_URL,
    session:{
        jwt:true
    },
    adapter: MongoDBAdapter(clientPromise, {
        databaseName: 'AuthDb'
      }),
    jwt:{
        secret: 'secretCode',
    },
    callbacks:{
        async jwt({token,user}){
            if(user){
                token.id = user.id
            }
            return token
        },
        async session(session,token) {
            session.user.id =token.id
            return session 
        }
    },
}); ```
Sign up to request clarification or add additional context in comments.

1 Comment

I came to this same conclusion, but why is the user thats passed into the session() callback undefined? It feels like it defeats the purpose of even providing user if you have to append the user to the token in the jwt() callback. Not sure if it's a NextAuth bug or what, but everyone seems to have this same "solution". I appreciate your workaround, though! Just confused
2

You can augment next-auth session types with @types/next-auth by adding an auth.d.ts file with the following:

import "next-auth";

declare module "next-auth" {
  interface User {
    id: string | number;
  }

  interface Session {
    user: User;
  }
}

More on this: https://github.com/nextauthjs/next-auth/issues/671

Comments

1

lets say this is your code

callbacks: {
async jwt({ token, user }) {

  token.user = user

  return token
},

So the very first time both token and user will have data, lets assume token and user will be in the structure

token = {
   id: "123",
   emeail: "[email protected]"
  }
 user = {
    name: "name"
    age: 34
   }

for some reason next-auth triggers this call back again and again but if you modify your code like

if(user) {
 token.user = user
  }

then if you console your token and user you can see, in those scenario where user is undefined token will have the user objet with it like

token = {
 id: "123",
 email: "[email protected]"
 user: {
  name: "name"
  age: 34
  }
 }
 user = undefined

so if you assigned the user to token with if condition whenever user comes undefined in next-auth, token will have user object inside it and vice versa. So either it will be

    token = {
      id: "123",
      email: "[email protected]"
      user: {
       name: "name"
       age: 34
       }
     }


 user = undefined

or

 token = {
   id: "123",
   email: "[email protected]"
   }


 user = {
    name: "name"
    age: 34
    }
   }

Comments

1

Pran R.V's answer is the best. Among the official doc and all the GitHub discussions and Stack Overflow questions, he is the first one that explained why we have to use if statement in the jwt callback. Literally no one else, including the official doc, has mentioned

for some reason next-auth triggers this call back again and again but if you modify your code like

This is why user object is always undefined in jwt and session callback.

Comments

0

The user object in this case should be coming from a database, not from discord. The session user property from discord doesn't have an id associated with it. The id property would be from your own user model in a database that you connected and you would need to use an adapter to access it.

Comments

0

When a user sign in next-auth try to call the JWT callback with the user object so here we need to use that user object and set it in token object like this:

async jwt({ token, user }) {
  if (user) {
    return { ...token, ...user };
  }
  return token;
}
async session({ session, token }) {
  session.user = token.user as any;// you can also declare type
  return session;
},

note that if you need to check if user is not undefined otherwise you're going to set the user as undefined.

Comments

0

I was having similar problem using authjs v5 (similar to next auth)

Code for auth.config.ts

import { User } from "./models";
import { connectToDb } from "./utils";

export const authConfig = {
 pages: {
  signIn: "/login",
 },
 providers: [],
 callbacks: {
   // FOR MORE DETAIL ABOUT CALLBACK FUNCTIONS CHECK https://next-auth.js.org/configuration/callbacks
  async jwt({ token, user }:any) {
    console.log('token',token,'user' ,user)
    if (user) {
      //-> Imp - Here I connected to my db, so I can get user from the database, as the user is actually accessible only once, for the very first time, it then becomes undefined, and this user is what u get from the Provide, google,
And I am putting that in token
      connectToDb();  
      const userFromDB = await User.findOne({ email: user.email });
      token.id = user.id; // This from the provider
      token.isAdmin = userFromDB.isAdmin; // This one from the database
    }
    return token;
  },
  async session({ session, token }:any) {
    console.log(token)
    if (token) {
      session.user.id = token.id;
      session.user.isAdmin = token.isAdmin;
    }
    return session;
  },
  authorized({ auth, request }:any) {
    const user = auth?.user;
    const isOnAdminPanel = request.nextUrl?.pathname.startsWith("/admin");
    const isOnBlogPage = request.nextUrl?.pathname.startsWith("/blog");
    const isOnLoginPage = request.nextUrl?.pathname.startsWith("/login");

    // ONLY ADMIN CAN REACH THE ADMIN DASHBOARD

    if (isOnAdminPanel && !user?.isAdmin) {
      return false;
    }

    // ONLY AUTHENTICATED USERS CAN REACH THE BLOG PAGE

    if (isOnBlogPage && !user) {
      return false;
    }

    // ONLY UNAUTHENTICATED USERS CAN REACH THE LOGIN PAGE

    if (isOnLoginPage && user) {
      return Response.redirect(new URL("/", request.nextUrl));
    }

    return true
  },
},

};

Comments

0

User will return undefined here:

async jwt({ token, user, account, profile }) {

or here:

async session({ session, token }) {

Because 'user' is only available the first time a user signs in

or when the user object is explicitly passed to the session update method

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.