Search code examples
typescriptnext.jsnext-auth

TypeScript issues in session callback


I'm trying to add the id property to the response of my API during login. I opted for using callbacks as suggested in this thread here (Get User ID from session in next-auth client), but I'm encountering the following error. While researching, I found a discussion about this on GitHub(https://github.com/nextauthjs/next-auth/issues/7132), and it seems to be a chronic TypeScript "bug". My question is, how can I proceed with this? Any suggestions, keeping in mind that my goal is simply to receive the id along with my response and manipulate it later. Currently, I receive the following API response:

enter image description here

ERROR:

enter image description here

The error starts inside the callback

callbacks: {
      session: async ({ session, token }) => {
        if (session?.user) {
          session.user.id = token.sub;
        }
        return session;
      },
      jwt: async ({ user, token }) => {
        if (user) {
          token.sub = user.id;
        }
        return token;
      },
  },

Next Auth configuration file

export const authOptions: NextAuthOptions = {
  adapter: PrismaAdapter(prisma as any),
  providers:[
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }),
    CredentialProvider({
      name: "credentials",
      credentials: {
        name: {label: "Name", type: "text", placeholder: "John Due"},
        email: {label: "Email", type: "text", placeholder: "jsmith"},
        password: {label: "Password", type: "password", placeholder: "password"},
      },
      async authorize(credentials, req): Promise<any>{
        console.log("Authorize method", credentials)
        
        if(!credentials?.email || !credentials?.password) throw new Error("Dados de login necessarios")
        const user = await prisma.user.findUnique({
          where:{
            email: credentials?.email
          }
        })
        if(!user || !user.hashedPassword) {
          throw new Error("Usuário não registrado")
        }

        const matchPassword = await bcrypt.compare(credentials.password, user.hashedPassword);
        if(!matchPassword)
         throw new Error("Senha incorreta")

        return user
      }
    })
  ],
  session: {
    strategy: "jwt",
    maxAge: 60 * 60,
  },
  jwt: { encode, decode },
  secret: process.env.NEXTAUTH_SECRET,
  callbacks: {
      session: async ({ session, token }) => {
        if (session?.user) {
          session.user.id = token.sub;
        }
        return session;
      },
      jwt: async ({ user, token }) => {
        if (user) {
          token.sub = user.id;
        }
        return token;
      },
  },
  debug: process.env.NODE_ENV === "development",
  pages: {
    signIn: "/dashboard"
  }
}
  • I tried reading the Next Auth documentation, but I couldn't find anything specific for this.

Solution

  • What you have is just a typescript error, because session.user doesn't include userId natively. So start by extending Session and JWT types in a next-auth.d.ts:

    import { EnumRole } from "@prisma/client"
    import NextAuth, { DefaultSession } from "next-auth"
    import { JWT } from "next-auth/jwt"
    import { Provider } from "next-auth/providers"
    
    declare module "next-auth" {
      /**
       * Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context
       */
      interface Session extends DefaultSession {
        user: {
          /** Id is the key you want to use for id in session */
          id: string;
        } & DefaultSession["user"]
      }
    }
    
    declare module "next-auth/jwt" {
        /** Returned by the `jwt` callback and `getToken`, when using JWT sessions */
        interface JWT {
          /** Sub is the key you want to use for user id in JWT */
          sub: string;
        }
    }