Search code examples
typescriptnext.jsnext-auth

How to use numeric user id with next-auth


I recently found and started testing create-t3-app as a new base for NextJS projects because it takes care of a lot of boilerplate setup for things like TypeScript, trpc, prisma, and next-auth so it'd save me a ton of time. While that's relevant, I don't think it's the source of my problem. My problem is that I use a MySQL database with auto-incrementing user IDs but it seems like the types for the next-auth package are forcing me to use a string (DefaultUser in next-auth/core/types.d.ts and AdapterUser in next-auth/adapters.d.ts both set the type of id to string and the comments say UUIDs). Thinking that I could possibly extend what's there to support numeric user IDs, I added this to next-auth.d.ts:

import { DefaultSession, DefaultUser } from 'next-auth'

declare module 'next-auth' {
  interface User extends DefaultUser {
    id: number;
  }
  interface Session {
    user?: {
      id: number;
    } & DefaultSession['user'];
  }
}

Which seems to work most places except in [...nextauth].ts where it is giving me this error

Type 'string | number' is not assignable to type 'number'. Type 'string' is not assignable to type 'number'.ts(2322)

On the session.user.id = user.id line in this section of code

export const authOptions: NextAuthOptions = {
  // Include user.id on session
  callbacks: {
    session({ session, user }) {
      if (session.user) {
        session.user.id = user.id
      }
      return session
    }
  },
  adapter: PrismaAdapter(prisma),
  providers: []
}

export default NextAuth(authOptions)

The TypeScript error goes away if I delete the id: string; line from the AdapterUser from next-auth/adapters.d.ts which then falls back to id: number; because I set that on User

export interface AdapterUser extends User {
    id: string; // <-- I removed this
    email: string;
    emailVerified: Date | null;
}

I don't think I should have to modify the library's types to support numeric user IDs but I'm all out of ideas how to solve this and haven't found answers online. Or should I not be using numeric IDs even though my database does? If it helps, I'm using

next 12.3.1
next-auth 4.12.3
react 18.2.0
react-dom 18.2.0
superjson 1.9.1
zod 3.18.0
eslint 8.22.0
postcss 8.4.14
prettier 2.7.1
prisma 4.4.0
tailwindcss 3.1.6
typescrypt 4.8.0

Solution

  • Unfortunately it doesn't seem possible to "patch up" or change the types the library has - even trying to change NextAuthOptions doesn't work since subsequent property definitions must have the same type. In the meantime, you'll have to use a runtime check/coercion or cast:

    export const authOptions: NextAuthOptions = {
      // Include user.id on session
      callbacks: {
        session({ session, user }) {
          if (session.user) {
            if (typeof user.id !== "number") throw new Error("id should a number");
            session.user.id = user.id // OK
            // session.user.id = +user.id // more dangerous but still works
            // session.user.id = user.id as number // also dangerous
          }
          return session
        }
      },
      adapter: PrismaAdapter(prisma),
      providers: []
    }