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

Next.js 14.0.3+next-auth+NestJS后端:开发正常构建失败

问题描述

基于Next.js 14.0.3开发应用,使用next-auth实现认证,外部NestJS后端处理授权与JWT验证。开发环境执行npm run dev时一切正常,但执行npm run build构建生产版本时遇到如下类型错误:

.next/types/app/api/auth/[...nextauth]/route.ts:8:13
Type error: Type 'OmitWithTag<typeof import("U:/sid/sid-front/app/api/auth/[...nextauth]/route"), "POST" | "GET" | "HEAD" | "OPTIONS" | "PUT" | "DELETE" | "PATCH" | "config" | "generateStaticParams" | "revalidate" | ... 5 more ... | "maxDuration", "">' does not satisfy the constraint '{ [x: string]: never; }'.
  Property 'authOptions' is incompatible with index signature.
    Type 'AuthOptions' is not assignable to type 'never'.

路由文件代码(app/api/auth/[...nextauth]/route.ts)

import { NextAuthOptions } from "next-auth";
import { JWT } from "next-auth/jwt";
import NextAuth from "next-auth/next";
import CredentialsProvider from "next-auth/providers/credentials";

async function refreshToken(token: JWT): Promise<JWT> {
  const res = await fetch(process.env.NEXT_PUBLIC_API_URL + "/auth/refresh", {
    method: "POST",
    headers: {
      authorization: `Refresh ${token.backendTokens.refreshToken}`,
    },
  });
  console.log("refreshed");

  const response = await res.json();

  return {
    ...token,
    backendTokens: response,
  };
}

export const authOptions: NextAuthOptions = {
  providers: [
    CredentialsProvider({
      name: "Credentials",
      credentials: {
        email: {
          label: "Email",
          type: "text",
          placeholder: "jsmith",
        },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials, req) {
        if (!credentials?.email || !credentials?.password) return null;
        const { email, password } = credentials;
        const res = await fetch(
          process.env.NEXT_PUBLIC_API_URL + "/auth/login",
          {
            method: "POST",
            body: JSON.stringify({
              email,
              password,
            }),
            headers: {
              "Content-Type": "application/json",
            },
          }
        );
        if (res.status == 401) {
          console.log(res.statusText);

          return null;
        }
        const user = await res.json();
        return user;
      },
    }),
  ],

  callbacks: {
    async jwt({ token, user }) {
      if (user) return { ...token, ...user };

      if (new Date().getTime() < token.backendTokens.expiresIn) return token;

      return await refreshToken(token);
    },

    async session({ token, session }) {
      session.user = token.user;
      session.backendTokens = token.backendTokens;

      return session;
    },
  },
};

const handler = NextAuth(authOptions);

export { handler as GET, handler as POST };

类型声明文件代码(next-auth.d.ts)

import NextAuth from "next-auth";

declare module "next-auth" {
  interface Session {
    user: {
      id: number;
      email: string;
      name: string;
    };
    backendTokens: {
      accessToken: string;
      refreshToken: string;
      expiresIn: number;
    };
  }
}

import { JWT } from "next-auth/jwt";

declare module "next-auth/jwt" {
  interface JWT {
    user: {
      id: number;
      email: string;
      name: string;
    };
    backendTokens: {
      accessToken: string;
      refreshToken: string;
      expiresIn: number;
    };
  }
}
原因分析与解决方法

原因

Next.js 14的App Router在生产构建阶段会严格校验API路由的导出内容:API路由文件只能导出HTTP方法处理函数(如GET、POST)以及Next.js允许的特殊配置项(如config),不能导出其他自定义变量。你当前代码中导出了authOptions,触发了类型检查的约束,导致构建失败。开发环境的类型检查规则相对宽松,所以没有暴露这个问题。

解决步骤

  1. 修改app/api/auth/[...nextauth]/route.ts中的authOptions定义,去掉export关键字,将其改为局部变量:
// 去掉前面的export
const authOptions: NextAuthOptions = {
  // 原配置内容不变
};
  1. 保存修改后,重新执行npm run build即可通过类型检查。

这个修改不会影响next-auth的功能,因为authOptions只需要在当前路由文件内被NextAuth()函数使用,不需要对外暴露。

内容的提问来源于stack exchange,提问作者Nazar Duma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 21:47:06