Next.js App Router中NextAuth Credentials结合argon2报错问题
问题分析
NextAuth v5 的 auth.config.ts 会在边缘运行时环境中执行,而 argon2(包括 @node-rs/argon2)依赖 Node.js 的 node:crypto 模块,边缘环境对 Node.js 核心模块的支持有限,且 webpack 默认不处理 node: 协议的导入,导致出现 UnhandledSchemeError。
解决方案
方案1:将密码验证移至服务端API路由(推荐)
API 路由完全在 Node.js 环境运行,可正常支持 argon2 依赖。
- 创建服务端 API 路由
app/api/auth/verify-password/route.ts:
import { NextResponse } from 'next/server' import { verifyPassword } from '@/utils/hash' export async function POST(request: Request) { const { password, hash } = await request.json() try { const isValid = await verifyPassword(password, hash) return NextResponse.json({ isValid }) } catch (err) { return NextResponse.json({ isValid: false }, { status: 500 }) } }
- 修改
auth.config.ts中的authorize函数,调用该 API:
import type { NextAuthConfig } from 'next-auth' import Credentials from 'next-auth/providers/credentials' import { LoginSchema } from './lib/zod' import { getUserByEmail } from './utils/db' export default { providers: [ Credentials({ async authorize(credentials: Partial<Record<string, unknown>>) { const validatedFields = LoginSchema.safeParse(credentials) if (!validatedFields.success) return null const { email, password } = validatedFields.data const user = await getUserByEmail(email) if (!user || !user.password) return null // 调用服务端API验证密码 const res = await fetch(`${process.env.NEXTAUTH_URL}/api/auth/verify-password`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ password, hash: user.password }), cache: 'no-store', }) const { isValid } = await res.json() if (isValid) return user return null }, }), ], } satisfies NextAuthConfig
方案2:配置Webpack处理node:协议(仅Node.js运行时可用)
如果你的项目使用 Node.js 运行时(而非 Edge Runtime),可修改 next.config.js 让 webpack 支持 node: 协议:
/** @type {import('next').NextConfig} */ const nextConfig = { webpack: (config) => { config.resolve.fallback = { ...config.resolve.fallback, crypto: require.resolve('crypto-browserify'), } // 处理node:协议前缀 config.resolve.plugins = [ ...(config.resolve.plugins || []), { apply(resolver) { resolver.hooks.resolve.tap('NodeProtocolResolver', (request) => { if (request.request.startsWith('node:')) { return { ...request, request: request.request.slice(5), } } }) }, }, ] return config }, } module.exports = nextConfig
注意:该方案在 Edge Runtime 环境下无效,因为边缘环境不支持
crypto-browserify这类模块。
额外说明
- bcrypt 可用是因为部分版本已兼容边缘环境,或其依赖模块被 webpack 正确处理。
@node-rs/argon2无效的原因和 argon2 一致,均依赖 Node.js 核心模块,无法在边缘环境运行。
内容的提问来源于stack exchange,提问作者Psypher
相关产品推荐
相关产品推荐

