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

使用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方法。

修复步骤:

  1. 修改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])
}
  1. 重新生成Prisma Client:
prisma generate
  1. 更新数据库结构:
prisma migrate dev
  1. 额外检查:确保../../../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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 19:45:15