使用NextAuth.js凭证提供者并设redirect:false时出现URL构造错误
问题:NextAuth.js凭证登录(redirect: false)触发URL构造错误
开发基于Next.js 13 App目录的应用,使用NextAuth.js做身份验证、Prisma操作数据库、PlanetScale作为数据库服务。在使用凭证提供者(Credentials Provider)并设置signIn({redirect: false})时,输入正确凭证后触发如下错误:
TypeError: Failed to construct 'URL': Invalid URL at _callee6$ (webpack-internal:///(app-client)/./node_modules/next-auth/react/index.js:337:21) at tryCatch (webpack-internal:///(app-client)/./node_modules/@babel/runtime/helpers/regeneratorRuntime.js:44:17) at Generator.eval (webpack-internal:///(app-client)/./node_modules/@babel/runtime/helpers/regeneratorRuntime.js:125:22) at Generator.eval [as next] (webpack-internal:///(app-client)/./node_modules/@babel/runtime/helpers/regeneratorRuntime.js:69:21) at asyncGeneratorStep (webpack-internal:///(app-client)/./node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24) at _next (webpack-internal:///(app-client)/./node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)
相关代码示例
auth.ts
const authOptions: NextAuthOptions = { adapter: PrismaAdapter(db), session: { strategy: 'jwt', }, pages: { signIn: '/login', }, providers: [ GoogleProvider({ clientId: envVariables.GOOGLE_CLIENT_ID, clientSecret: envVariables.GOOGLE_CLIENT_SECRET, }), Credentials({ name: 'credentials', credentials: { email: { label: 'email', type: 'email', placeholder: 'wantnewstyle@mail.com', }, password: { label: 'password', type: 'password', }, }, async authorize(credentials) { if (!credentials) { throw new Error('Грешни данни'); } const dbUser = await db.user.findFirst({ where: { email: credentials.email, }, }); if (!dbUser) { throw new Error('Грешен имейл'); } // Check if passwords match const checkPassword = await bcrypt.compare( credentials.password, dbUser?.password ?? '' ); if (!checkPassword) { throw new Error('Грешна парола'); } return dbUser; }, }), ], callbacks: { session({ token, session }) { if (token) { // eslint-disable-next-line no-param-reassign session.user.id = token.id; // eslint-disable-next-line no-param-reassign session.user.name = token.name; // eslint-disable-next-line no-param-reassign session.user.firstName = token.firstName; // eslint-disable-next-line no-param-reassign session.user.lastName = token.lastName; // eslint-disable-next-line no-param-reassign session.user.phone = token.phone; // eslint-disable-next-line no-param-reassign session.user.email = token.email; // eslint-disable-next-line no-param-reassign session.user.image = token.picture; // eslint-disable-next-line no-param-reassign session.user.isBarber = token.isBarber; } return session; }, async jwt({ token, user }) { const dbUser = await db.user.findFirst({ where: { email: token.email, }, include: { barber: true, }, }); if (!dbUser) { // eslint-disable-next-line no-param-reassign token.id = user!.id; return token; } return { id: dbUser.id, firstName: dbUser.firstName!, lastName: dbUser.lastName!, email: dbUser.email, picture: dbUser.image, phone: dbUser.phone!, isBarber: dbUser.barber !== null, }; }, redirect() { return '/'; }, }, }; export default authOptions;
login-form.tsx
async function onSubmit(values: z.infer<typeof loginSchema>) { const result = await signIn('credentials', { email: values.email, password: values.password, redirect: false, }); if (result?.error === 'Грешен имейл') { form.setError('email', { message: result.error, }); return; } if (result?.error === 'Грешна парола') { form.setError('password', { message: result.error, }); return; } await wait(3000); redirect('/'); } }
排查与修复建议
- 确认NEXTAUTH_URL环境变量配置:NextAuth.js依赖该变量生成回调URL,即使
redirect: false也会用到。开发环境需设置为http://localhost:3000,生产环境设置为实际域名,确保无拼写错误。 - 移除硬编码的redirect回调:当前authOptions中的
redirect() { return '/' }会覆盖NextAuth的默认URL处理逻辑,尤其是在redirect: false场景下可能引发冲突。尝试注释或删除该回调,让框架使用默认行为。 - 验证authorize返回的用户对象完整性:确保authorize函数返回的用户对象包含id、email等核心字段,虽然当前代码逻辑看似正确,但不完整的对象可能间接导致URL构造异常。
- 升级NextAuth.js版本:该错误可能是特定版本的已知bug,尝试升级到最新稳定版,查看是否已修复相关问题。
内容的提问来源于stack exchange,提问作者Dimitar D.
相关产品推荐
相关产品推荐

