Búsqueda de sitios web

next auth - Credenciales de NextAuth con Typescript


Estoy intentando usar NextAuth Credentials con Typescript, pero siempre muestra un error de tipo así, solo copié el ejemplo del documento pero no puedo ejecutarlo correctamente: Aquí está el código de /pages/auth/[...nextauth].ts

return await NextAuth(req, res, {
    providers: [
      CredentialsProvider({
        name: 'Credentials',
        credentials: {
          email: { label: 'Email', type: 'email' },
          password: { label: 'Password', type: 'password' },
        },
        async authorize(credentials, req) {
          const { email, password } = credentials as { email: string; password: string; };
          const { user } = await loginUser({ email, password });
          if (!user) {
            return null;
          }
          return user;
        },
      }),
    ],
    callbacks: {
      session({ session, token, user }) {
        return session;
      },
      async jwt({ token }) {
        return token;
      },
    },
    adapter: PrismaAdapter(prisma),
  });

La función authorize siempre muestra este error de verificación de tipo:

Type '(credentials: Record<"email" | "password", string> | undefined, res: Pick<RequestInternal, "query" | "body" | "headers" | "method">) => Promise<...>' is not assignable to type '(credentials: Record<"email" | "password", string> | undefined, req: Pick<RequestInternal, "query" | "body" | "headers" | "method">) => Awaitable<...>'.
  Type 'Promise<User | null>' is not assignable to type 'Awaitable<User | null>'.
    Type 'Promise<User | null>' is not assignable to type 'PromiseLike<User | null>'.
      Types of property 'then' are incompatible.
        Type '<TResult1 = User | null, TResult2 = never>(onfulfilled?: ((value: User | null) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<...>) | null | undefined) => Promise<...>' is not assignable to type '<TResult1 = User | null, TResult2 = never>(onfulfilled?: ((value: User | null) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<...>) | null | undefined) => PromiseLike<...>'.
          Types of parameters 'onfulfilled' and 'onfulfilled' are incompatible.
            Types of parameters 'value' and 'value' are incompatible.
              Type 'import("/app/node_modules/.prisma/client/index").User | null' is not assignable to type 'import("/app/node_modules/next-auth/core/types").User | null'.
                Type 'import("/app/node_modules/.prisma/client/index").User' is not assignable to type 'import("/app/node_modules/next-auth/core/types").User'.
                  Types of property 'id' are incompatible.
                    Type 'number' is not assignable to type 'string'.ts(2322)
credentials.d.ts(13, 5): The expected type comes from property 'authorize' which is declared here on type 'UserCredentialsConfig<{ email: { label: string; type: string; }; password: { label: string; type: string; }; }>'

Agregué esta definición de tipo a types/next-auth.d.ts

import 'next-auth';
import { User as UserModel } from '@prisma/client';

declare module 'next-auth' {
  interface User extends UserModel {}

  interface Session {
    user: User;
    expires: string;
  }
}

pero el error todavía está ahí

Aquí está la función loginUser

import { compare } from 'bcryptjs';

import prisma from '@/libs/prisma';
import { User } from '@prisma/client';
import { UserLoginData } from '@/types/auth';

export const LoginUser = async ({
  email,
  password,
}: UserLoginData): Promise<{
  user: User | null;
  error: Error | null;
}> => {
  const user = await prisma.user.findUnique({ where: { email } });

  if (!user) {
    return {
      user: null,
      error: new Error(`User with email: ${email} does not exist.`),
    };
  }

  const isValid = password && user.password && (await compare(password, user.password));

  if (!isValid) {
    return {
      user,
      error: new Error('Invalid password.'),
    };
  }

  return { user, error: null };
};

Respuesta #1

Lo resolví porque en mi esquema de Prisma, declaré el campo id con el tipo number y el campo id de "next-auth" es string, así que necesito extender la interfaz del núcleo y agregar la definición de id como number para que coincida con mi esquema de Prisma ¡y ahora funciona!

import NextAuth, { DefaultSession } from 'next-auth';
import { User as UserModel } from '@prisma/client';

declare module 'next-auth' {
  interface User extends UserModel {
    id: number; // <- here it is
  }
}

Respuesta #2

Esta es una versión más corta de la solución de @Hai Nguyen, y también funciona.

import NextAuth from 'next-auth';

declare module 'next-auth' {
  interface User {
    id: number; // <- here it is
  }
}