使用Prisma+Next-Auth的EmailProvider登录时出现CreateVerificationTokenError错误
NextAuth + Prisma适配器Email登录失败问题排查
使用NextAuth搭配Prisma适配器实现Email登录功能时,点击登录按钮可正常打开/signin页面,但通过Email Provider登录时失败,报错信息如下:
[next-auth][error][SIGNIN_EMAIL_ERROR] https://next-auth.js.org/errors#signin_email_error Cannot read properties of undefined (reading 'create') { error: TypeError: Cannot read properties of undefined (reading 'create') at createVerificationToken (C:\Users\Simon Palmer\Documents\Programming\ideally\frontend\node_modules\@next-auth\prisma-adapter\dist\index.js:37:65) at _callee2$ (C:\Users\Simon Palmer\Documents\Programming\ideally\frontend\node_modules\next-auth\core\errors.js:365:29) at tryCatch (C:\Users\Simon Palmer\Documents\Programming\ideally\frontend\node_modules\@babel\runtime\helpers\regeneratorRuntime.js:44:17) at Generator.<anonymous> (C:\Users\Simon Palmer\Documents\Programming\ideally\frontend\node_modules\@babel\runtime\helpers\regeneratorRuntime.js:125:22) at Generator.next (C:\Users\Simon Palmer\Documents\Programming\ideally\frontend\node_modules\@babel\runtime\helpers\regeneratorRuntime.js:69:21) at asyncGeneratorStep (C:\Users\Simon Palmer\Documents\Programming\ideally\frontend\node_modules\@babel\runtime\helpers\asyncToGenerator.js:3:24) at _next (C:\Users\Simon Palmer\Documents\Programming\ideally\frontend\node_modules\@babel\runtime\helpers\asyncToGenerator.js:22:9) at C:\Users\Simon Palmer\Documents\Programming\ideally\frontend\node_modules\@babel\runtime\helpers\asyncToGenerator.js:27:7 at new Promise (<anonymous>) at Object.createVerificationToken (C:\Users\Simon Palmer\Documents\Programming\ideally\frontend\node_modules\@babel\runtime\helpers\asyncToGenerator.js:19:12) { name: 'CreateVerificationTokenError', code: undefined }, providerId: 'email', message: "Cannot read properties of undefined (reading 'create')" }
相关代码文件
1. NextAuth配置文件(pages/api/auth/[...nextauth].ts)
import { NextApiHandler } from 'next'; import NextAuth from 'next-auth'; import { PrismaAdapter } from '@next-auth/prisma-adapter'; import EmailProvider from "next-auth/providers/email"; import LinkedInProvider from 'next-auth/providers/linkedin'; import { prisma } from '../../../common/prisma/lib/prisma'; const authHandler: NextApiHandler = (req, res) => NextAuth(req, res, options); export default authHandler; const options = { providers: [ LinkedInProvider({ clientId: process.env.LINKEDIN_ID!, clientSecret: process.env.LINKEDIN_SECRET!, }), EmailProvider({ server: process.env.EMAIL_SERVER, from: process.env.EMAIL_FROM, }), ], adapter: PrismaAdapter(prisma), secret: process.env.SECRET, };
2. 登录按钮组件(Header.tsx)
// Header.tsx import React from 'react'; import Link from 'next/link'; import { useRouter } from 'next/router'; import { signIn, signOut, useSession } from 'next-auth/react'; const Header: React.FC = () => { const { data: session } = useSession() if (session) { console.log(session) return ( <> Signed in as {session.user.email} <br /> <button onClick={() => signOut()}>Sign out</button> </> ) } return ( <> Not signed in <br /> <button onClick={() => signIn()}>Sign in</button> </> ) }; export default Header;
3. Prisma Schema文件
generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } // schema.prisma model Account { id String @id @default(cuid()) userId String type String provider String providerAccountId String refresh_token String? @db.Text access_token String? @db.Text expires_at Int? token_type String? scope String? id_token String? @db.Text session_state String? user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([provider, providerAccountId]) } model Session { id String @id @default(cuid()) sessionToken String @unique userId String expires DateTime user User @relation(fields: [userId], references: [id], onDelete: Cascade) } model User { id String @id @default(cuid()) name String? email String? @unique emailVerified DateTime? @map("email_verified") image String? createdAt DateTime? updatedAt DateTime? social Json? accounts Account[] sessions Session[] } model VerificationToken { identifier String token String @unique expires DateTime @@unique([identifier, token]) }
4. .env配置
NEXTAUTH_URL="http://localhost:3000/" # Email OAuth EMAIL_SERVER="smtp://username:password@smtp.gmail.com:465" EMAIL_FROM="name@gmail.com"
解决方案
报错核心原因是Prisma Client无法找到VerificationToken模型的create方法,根源在于你的Prisma Schema中VerificationToken模型缺少主键定义,导致Prisma生成的Client没有生成完整的CRUD方法。
修复步骤:
- 修改VerificationToken模型,添加主键定义,推荐使用NextAuth官方指定的复合主键结构:
model VerificationToken { identifier String token String @unique expires DateTime @@id([identifier, token]) @@unique([identifier, token]) }
或者也可以添加单独的id主键:
model VerificationToken { id String @id @default(cuid()) identifier String token String @unique expires DateTime @@unique([identifier, token]) }
- 重新生成Prisma Client:
prisma generate
- 更新数据库结构:
prisma migrate dev
- 额外检查:确保
../../../common/prisma/lib/prisma.ts中正确初始化并导出Prisma Client实例,示例代码:
import { PrismaClient } from '@prisma/client' const prisma = new PrismaClient() export default prisma
完成以上步骤后,Email Provider的登录功能应该可以正常工作。
内容的提问来源于stack exchange,提问作者Simon Palmer
相关产品推荐
相关产品推荐

