You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextAuth.js TypeScript中authorize函数类型不兼容问题求助

解决NextAuth.js Credentials Provider中authorize函数的类型不匹配问题

问题场景

基于Next.js 13.5.4 + NextAuth.js ^4.23.2的TypeScript项目中,使用Credentials Provider时,api/auth/[...nextauth]/route.ts里的authorize函数出现类型错误。

相关代码

api/auth/[...nextauth]/route.ts片段:

CredentialsProvider({
        name: 'credentials',
        credentials: {},

        async authorize(credentials: any) {
            const {email, password} = credentials

            try {
                const user = await prisma.user.findFirst({
                    where: {
                        email: email
                    }
                })

                if (!user) {
                    return null
                }

                const passwordMatch = await bcrypt.compare(password, user.password)
                if (!passwordMatch) {
                    return null
                }

                return user
            } catch (error) {
                console.error("ERROR AuthOptions: ", error);                    
            }
        },
    }),

错误信息

Type '(credentials: any) => Promise<{ id: number; firstName: string; lastName: string; email: string; password: string; telephone: string; createdAt: Date; updatedAt: Date; }>' is not assignable to type '(credentials: Record<never, string>, req: Pick<RequestInternal, "body" | "query" | "headers" | "method">) => Awaitable<User>'.
  Type 'Promise<{ id: number; firstName: string; lastName: string; email: string; password: string; telephone: string; createdAt: Date; updatedAt: Date; }>' is not assignable to type 'Awaitable<User>'.
    Type 'Promise<{ id: number; firstName: string; lastName: string; email: string; password: string; telephone: string; createdAt: Date; updatedAt: Date; }>' is not assignable to type 'PromiseLike<User>'.
      Types of property 'then' are incompatible.
        Type '<TResult1 = { id: number; firstName: string; lastName: string; email: string; password: string; telephone: string; createdAt: Date; updatedAt: Date; }, TResult2 = never>(onfulfilled?: (value: { id: number; firstName: string; ... 5 more ...; updatedAt: Date; }) => TResult1 | PromiseLike<...>, onrejected?: (reason: an...' is not assignable to type '<TResult1 = User, TResult2 = never>(onfulfilled?: (value: User) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>) => PromiseLike<...>'.
          Types of parameters 'onfulfilled' and 'onfulfilled' are incompatible.
            Types of parameters 'value' and 'value' are incompatible.
              Type '{ id: number; firstName: string; lastName: string; email: string; password: string; telephone: string; createdAt: Date; updatedAt: Date; }' is not assignable to type 'User'.
                Types of property 'id' are incompatible.
                  Type 'number' is not assignable to type 'string'.

ts.config配置

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}

错误原因

NextAuth.js默认的User类型规定id为字符串类型,但你的Prisma用户模型中id是数字类型,同时返回的用户对象包含了password字段(该字段不属于默认User类型),导致类型不兼容。

解决方案

方案1:转换用户字段类型并过滤敏感信息

直接修改authorize函数的返回值,将id转为字符串,同时过滤掉password字段(避免暴露敏感数据+符合类型要求):

async authorize(credentials: { email?: string; password?: string }) {
    const { email, password } = credentials;
    if (!email || !password) return null;

    try {
        const user = await prisma.user.findFirst({
            where: { email }
        });

        if (!user) return null;

        const passwordMatch = await bcrypt.compare(password, user.password);
        if (!passwordMatch) return null;

        // 转换id为字符串,过滤password字段
        return {
            id: user.id.toString(),
            firstName: user.firstName,
            lastName: user.lastName,
            email: user.email,
            telephone: user.telephone,
            createdAt: user.createdAt,
            updatedAt: user.updatedAt
        };
    } catch (error) {
        console.error("ERROR AuthOptions: ", error);
        return null; // 确保异常时也返回null,符合Awaitable<User | null>类型
    }
}

同时给credentials定义明确的类型,替换原来的any,提升类型安全性。

方案2:自定义NextAuth的User类型(保留数字id)

如果不想转换id类型,可以扩展NextAuth的默认类型,让它适配你的用户模型:

  1. 在项目根目录创建types/next-auth.d.ts文件:
import NextAuth from "next-auth";

declare module "next-auth" {
    interface User {
        id: number;
        firstName: string;
        lastName: string;
        email: string;
        telephone: string;
        createdAt: Date;
        updatedAt: Date;
        // 不要包含password字段,避免敏感数据暴露
    }
}
  1. 修改tsconfig.json的include数组,确保包含自定义类型文件:
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "types/**/*.ts"],
  1. 回到authorize函数,过滤掉password字段后返回用户:
return {
    id: user.id,
    firstName: user.firstName,
    lastName: user.lastName,
    email: user.email,
    telephone: user.telephone,
    createdAt: user.createdAt,
    updatedAt: user.updatedAt
};

额外注意点

  • 永远不要把用户的password字段返回给前端,既不符合NextAuth的类型要求,也存在严重的安全风险。
  • 确保authorize函数的返回值始终符合Awaitable<User | null>类型,异常场景下也要返回null,避免类型错误。

内容的提问来源于stack exchange,提问作者Tharisha Perera

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 03:24:52