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
相关产品推荐
相关产品推荐

