Home > Software engineering >  NextAuth Credentials with Typescript
NextAuth Credentials with Typescript

Time:01-22

I'm trying to use NextAuth Credentials with Typescript, but it's always showing a type error like this, I just copied the example from the document but cannot run it properly: Here is the code from /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),
  });

the authorize function always show this type checking error: enter image description here

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; }; }>'

I added this type definition to 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;
  }
}

but the error is still there

Here is loginUser function

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 };
};

CodePudding user response:

It looks like the error is occurring because the credentials object passed to the authorize function is not being properly typed. The credentials object is an object that contains properties for each of the fields defined in the credentials property of the CredentialsProvider configuration.

To fix this, you can use a type that describes the shape of the credentials object. You can create a type that describes the shape of the credentials object, and then use it as the type of the credentials parameter in the authorize function.

Here's an example of how you could define the type and use it in your code:

type Credentials = {
  email: string;
  password: string;
};

return await NextAuth(req, res, {
    providers: [
      CredentialsProvider({
        name: 'Credentials',
        credentials: {
          email: { label: 'Email', type: 'email' },
          password: { label: 'Password', type: 'password' },
        },
        async authorize(credentials: Credentials, res) {
          const { email, password } = credentials;
          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),
  });

CodePudding user response:

The error message is indicating that the 'authorize' function in your code is not correctly typed. It is expecting the 'req' parameter to be of type 'Pick<RequestInternal, "query" | "body" | "headers" | "method">' but you're passing in 'res' which is of a different type. To fix this, make sure that you are passing in the correct parameter to the 'authorize' function.

In addition, it looks like there might be some type mismatches between the types of 'user' you're returning from your 'loginUser' function and the types that NextAuth is expecting. It's difficult to say for sure without more information about the 'loginUser' function, but you might need to cast the 'user' property to the correct type or make sure the types of 'user' in your 'loginUser' function and 'NextAuth' match.

Also, you have added types to 'next-auth' module in 'types/next-auth.d.ts' but it is not being recognized. You need to make sure that the 'types' folder is in the root of the project and it is included in the 'tsconfig.json' file.

You should also make sure that the version of 'next-auth' you are using is compatible with the version of TypeScript you are using.

  • Related