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

NextAuth登录异常:跳转至/api/auth/error而非显示错误信息

NextAuth登录功能问题:错误跳转与TypeError异常

问题描述

无论用户输入正确或错误的用户名和密码,页面都会跳转到/api/auth/error,无法在自定义的/auth/signin登录页显示错误提示;同时服务器终端抛出TypeError: Cannot read properties of undefined (reading 'map')错误。需求是当用户输入错误账号密码时,在登录页展示对应的错误信息。

服务器错误日志

⨯ TypeError: Cannot read properties of undefined (reading 'map')
    at setEnvDefaults (webpack-internal:///(rsc)/./node_modules/@auth/core/lib/utils/env.js:37:41)
    at setEnvDefaults (webpack-internal:///(rsc)/./node_modules/next-auth/lib/env.js:41:67)
    at NextAuth (webpack-internal:///(rsc)/./node_modules/next-auth/index.js:139:64)
    at GET (webpack-internal:///(rsc)/./src/app/api/auth/[...nextauth]/route.ts:66:65)
    at /Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:55044
    at /Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/server/lib/trace/tracer.js:140:36
    at NoopContextManager.with (/Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/compiled/@opentelemetry/api/index.js:1:7062)
    at ContextAPI.with (/Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/compiled/@opentelemetry/api/index.js:1:518)
    at NoopTracer.startActiveSpan (/Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/compiled/@opentelemetry/api/index.js:1:18093)
    at ProxyTracer.startActiveSpan (/Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/compiled/@opentelemetry/api/index.js:1:18854)
    at /Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/server/lib/trace/tracer.js:122:103
    at NoopContextManager.with (/Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/compiled/@opentelemetry/api/index.js:1:7062)
    at ContextAPI.with (/Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/compiled/@opentelemetry/api/index.js:1:518)
    at NextTracerImpl.trace (/Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/server/lib/trace/tracer.js:122:28)
    at /Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:47853
    at AsyncLocalStorage.run (node:async_hooks:346:14)
    at Object.wrap (/Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:40244)
    at /Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:46429
    at AsyncLocalStorage.run (node:async_hooks:346:14)
    at Object.wrap (/Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:37583)
    at /Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:46391
    at AsyncLocalStorage.run (node:async_hooks:346:14)
    at ek.execute (/Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:45838)
    at ek.handle (/Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:56303)
    at doRender (/Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/server/base-server.js:1357:60)
    at cacheEntry.responseCache.get.routeKind (/Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/server/base-server.js:1567:46)
    at ResponseCache.get (/Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/server/response-cache/index.js:49:26)
    at DevServer.renderToResponseWithComponentsImpl (/Users/apple/Dev/prongs_of_wisdom/node_modules/next/dist/server/base-server.js:1487:53)
 GET /api/auth/providers 500 in 234ms
 GET /api/auth/error 500 in 9ms
 GET /auth/signin 200 in 87ms

相关代码

src/app/api/[...nextauth]/route.ts

import NextAuth from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
import connectToDatabase from '@/lib/mongodb';
import User from '@/models/User';
import bcrypt from 'bcryptjs';

export const authOptions = {
  providers: [
    CredentialsProvider({
      name: 'Credentials',
      credentials: {
        username: { label: 'Username', type: 'text' },
        password: { label: 'Password', type: 'password' },
      },
      async authorize(credentials) {
        console.log(credentials)
        await connectToDatabase();

        const user = await User.findOne({ username: credentials?.username });
        console.log("User===", user);
        if (user && bcrypt.compareSync(credentials?.password|| '', user.password)) {
          return { id: user._id, name: user.username };
        } else {
          return null;
        }
      },
    }),
  ],
  pages: {
    signIn: '/auth/signin', // Customize the sign-in page route
    // Optionally, add signUp page route if needed
    signUp: '/auth/signup',
  },
  session: {
    strategy: 'jwt',
  },
  callbacks: {
    async redirect({ url, baseUrl }) {
      // Redirect to home page or any specific page upon successful sign-in
      return url.startsWith(baseUrl) ? url : baseUrl;
    },
  },
};

export async function GET(request: Request) {
  return NextAuth(request, authOptions);
}

export async function POST(request: Request) {
  return NextAuth(request, authOptions);
}

src/app/auth/signin/page.tsx

"use client";

import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { signIn } from 'next-auth/react';

export default function SignIn() {
  const [errorMessage, setErrorMessage] = useState<string | null>(null);

  const handleOnSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    const username = (event.target as HTMLFormElement).username.value;
    const password = (event.target as HTMLFormElement).password.value;

    const result = await signIn("credentials", {
      redirect: false,
      username,
      password,
    });

    if (result?.error) {
      setErrorMessage("Invalid username or password");
    } else {
      // window.location.href = "/";
    }
  };

  return (
    <div className="flex items-center justify-center min-h-screen">
      <div className="lg:w-1/3 md:w-2/3 bg-white p-8 rounded shadow-lg">
        <h1 className="text-2xl mb-4">Sign In</h1>

        {errorMessage && <p className="text-red-500">{errorMessage}</p>}

        <form className="py-10" onSubmit={handleOnSubmit}>
          <input
            name="username"
            type="text"
            placeholder="Username"
            required
            className="border mb-4 p-2 w-full"
          />
          <input
            name="password"
            type="password"
            placeholder="Password"
            required
            className="border mb-4 p-2 w-full"
          />
          <button
            type="submit"
            className="bg-blue-500 text-white py-2 px-4 rounded w-full"
          >
            Sign in with Credentials
          </button>
        </form>
        <button
          className="bg-green-600 text-white py-2 px-4 rounded mb-4"
          onClick={() => signIn("google")}
        >
          Sign in with Google
        </button>
      </div>
    </div>
  );
}

解决方案

1. 修复环境变量缺失问题

服务器抛出的map类型错误,核心原因是缺少NextAuth必需的NEXTAUTH_SECRET环境变量:

  • 在项目根目录创建.env.local文件,添加以下内容:
    NEXTAUTH_SECRET=your-secret-key-here
    
  • 可以通过终端命令生成安全密钥:openssl rand -hex 32,将生成的字符串替换上述your-secret-key-here。

2. 完善认证逻辑的错误返回

当前authorize函数验证失败时返回null,会触发NextAuth默认的错误跳转。修改为抛出明确错误,让客户端能捕获错误信息:

async authorize(credentials) {
  if (!credentials?.username || !credentials?.password) {
    throw new Error("请输入用户名和密码");
  }
  await connectToDatabase();

  const user = await User.findOne({ username: credentials.username });
  if (!user) {
    throw new Error("用户名不存在");
  }
  if (!bcrypt.compareSync(credentials.password, user.password)) {
    throw new Error("密码错误");
  }
  return { id: user._id, name: user.username };
},

3. 优化登录页错误提示展示

修改登录页的错误处理逻辑,直接显示后端返回的具体错误信息:

if (result?.error) {
  setErrorMessage(result.error);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 21:25:53