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

Next.js 14及以上版本Next-Auth Google Provider OAuthCallback错误

NextAuth + Google Provider 登录JWT过期错误问题

我使用NextAuth结合Google Provider实现登录功能,已创建下拉菜单,用户点击登录按钮后会跳转到api/auth/signin?callbackUrl=http%3A%2F%2Flocalhost%3A3000%2F页面,选择Google登录并完成邮箱密码验证后,未跳转回应用,反而出现错误。

错误日志

GET /api/auth/providers 200 in 30ms
 GET /api/auth/signin?callbackUrl=http%3A%2F%2Flocalhost%3A3000%2F 200 in 33ms
 POST /api/auth/signin/google 302 in 1211ms
[next-auth][error][OAUTH_CALLBACK_ERROR] 
https://next-auth.js.org/errors#oauth_callback_error JWT expired, now 1715240896, exp 1715201013 {
  error: RPError: JWT expired, now 1715240896, exp 1715201013
      at Client.validateJWT (webpack-internal:///(rsc)/./node_modules/openid-client/lib/client.js:864:23)     
      at Client.validateIdToken (webpack-internal:///(rsc)/./node_modules/openid-client/lib/client.js:651:64) 
      at Client.callback (webpack-internal:///(rsc)/./node_modules/openid-client/lib/client.js:430:24)        
      at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
      at async oAuthCallback (webpack-internal:///(rsc)/./node_modules/next-auth/core/lib/oauth/callback.js:109:16)
      at async Object.callback (webpack-internal:///(rsc)/./node_modules/next-auth/core/routes/callback.js:52:11)
      at async AuthHandler (webpack-internal:///(rsc)/./node_modules/next-auth/core/index.js:208:28)
      at async NextAuthRouteHandler (webpack-internal:///(rsc)/./node_modules/next-auth/next/index.js:69:28)  
      at async NextAuth._args$ (webpack-internal:///(rsc)/./node_modules/next-auth/next/index.js:105:16)      
      at async C:\Next\ecommerce-yt\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:53446
      at async e_.execute (C:\Next\ecommerce-yt\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:44747)
      at async e_.handle (C:\Next\ecommerce-yt\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:54700)
      at async doRender (C:\Next\ecommerce-yt\node_modules\next\dist\server\base-server.js:1377:42)
      at async cacheEntry.responseCache.get.routeKind (C:\Next\ecommerce-yt\node_modules\next\dist\server\base-server.js:1587:40)
      at async DevServer.renderToResponseWithComponentsImpl (C:\Next\ecommerce-yt\node_modules\next\dist\server\base-server.js:1507:28)
      at async DevServer.renderPageComponent (C:\Next\ecommerce-yt\node_modules\next\dist\server\base-server.js:1924:24)
      at async DevServer.renderToResponseImpl (C:\Next\ecommerce-yt\node_modules\next\dist\server\base-server.js:1962:32)
      at async DevServer.pipeImpl (C:\Next\ecommerce-yt\node_modules\next\dist\server\base-server.js:920:25)  
      at async NextNodeServer.handleCatchallRenderRequest (C:\Next\ecommerce-yt\node_modules\next\dist\server\next-server.js:272:17)
      at async DevServer.handleRequestImpl (C:\Next\ecommerce-yt\node_modules\next\dist\server\base-server.js:816:17)
      at async C:\Next\ecommerce-yt\node_modules\next\dist\server\dev\next-dev-server.js:339:20
      at async Span.traceAsyncFn (C:\Next\ecommerce-yt\node_modules\next\dist\trace\trace.js:154:20)
      at async DevServer.handleRequest (C:\Next\ecommerce-yt\node_modules\next\dist\server\dev\next-dev-server.js:336:24)
      at async invokeRender (C:\Next\ecommerce-yt\node_modules\next\dist\server\lib\router-server.js:174:21)  
      at async handleRequest (C:\Next\ecommerce-yt\node_modules\next\dist\server\lib\router-server.js:353:24) 
      at async requestHandlerImpl (C:\Next\ecommerce-yt\node_modules\next\dist\server\lib\router-server.js:377:13)
      at async Server.requestListener (C:\Next\ecommerce-yt\node_modules\next\dist\server\lib\start-server.js:141:13) {
    name: 'OAuthCallbackError',
    code: undefined
  },
  providerId: 'google',
  message: 'JWT expired, now 1715240896, exp 1715201013'
}
 GET /api/auth/callback/google?state=WbD1LDf6r0mseWQw3LNo9BWSxlc38QT6L3ZDbe29GvY&code=4%2F0AdLIrYdC9MZFw5WH9ZlesxYhtcDRf7-XRN0rNEwSRZraX_9gUGYwdGe7YJ-6Y9ySbLeHcw&scope=email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+openid&authuser=0&prompt=none 302 in 1890ms
 GET /api/auth/error?error=OAuthCallback 302 in 42ms
 GET /api/auth/signin?error=OAuthCallback 200 in 31ms

相关代码

1. UserMenuButton.tsx

"use client"
import { Session } from 'next-auth'
import { signIn, signOut } from 'next-auth/react'
import Image from 'next/image'
import React from 'react'
interface UserMenuButtonProps{
    session:Session | null
}
const UserMenuButton = ({ session }: UserMenuButtonProps) => {
    const user = session?.user;
  return (
      <div className='dropdown dropdown-end'>
          <label tabIndex={0} className='btn btn-ghost btn-circle'>
              {user ? <Image src={user?.image || "abc"} alt={user?.email || "user email"} height={40} width={40} className='w-10 rounded-full'/> :   <svg
            xmlns="http://www.w3.org/2000/svg"
            fill="none"
            viewBox="0 0 24 24"
            className="inline-block h-5 w-5 stroke-current"
          >
            <path
              strokeLinecap="round"
              strokeLinejoin="round"
              strokeWidth="2"
              d="M5 12h.01M12 12h.01M19 12h.01M6 12a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0z"
            />
          </svg>}
          </label>
          <ul tabIndex={0} className='dropdown-content menu rounded-box menu-sm z-30 mt-3 w-52 bg-base-100 p-2 shadow'>
              <li>{ user ? <button onClick={()=>signOut({callbackUrl:"/"})}>Sign Out</button>: <button onClick={()=>signIn()}>Sign In</button>}</li>
          </ul>
    </div>
  )
}

export default UserMenuButton

2. route.tsx

import prisma from "@/lib/db/prisma";
import { env } from "@/lib/env";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { NextAuthOptions } from "next-auth";
import { Adapter } from "next-auth/adapters";
import NextAuth from "next-auth/next";
import GoogleProvider from "next-auth/providers/google";

export const authOptions: NextAuthOptions = {
  adapter: PrismaAdapter(prisma) as Adapter,
  providers: [
    GoogleProvider({
      clientId: env.GOOGLE_CLIENT_ID,
      clientSecret: env.GOOGLE_CLIENT_SECRET,
    }),
  ],
  // ... other NextAuth options
  events: {
    async signIn({ user }) {
      // Perform any user-related actions after successful sign-in (e.g., database updates)
      // Ensure this logic is optimized and doesn't introduce significant delays
      console.log("User signed in:", user);
      // ...
    },
  },
  // ... other NextAuth options (e.g., session)
};

const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };

解决方案

这个错误核心原因是本地服务器时间与Google服务器时间不一致,导致验证JWT时判定过期。按以下步骤解决:

  1. 同步本地系统时间

    • Windows:打开设置→时间和语言→开启自动设置时间,同步到互联网时间服务器。
    • Mac:系统设置→通用→日期与时间→勾选"自动设置日期与时间"。
    • Linux:执行sudo timedatectl set-ntp true开启自动时间同步。
  2. 检查Google OAuth配置

    • 确认Google Cloud控制台中,OAuth客户端的授权重定向URI为http://localhost:3000/api/auth/callback/google(开发环境)。
    • 验证环境变量中的GOOGLE_CLIENT_ID和GOOGLE_CLIENT_SECRET配置正确,未过期。
  3. 临时绕过JWT验证(仅开发环境)
    若时间同步后仍有问题,可在Google Provider配置中添加idTokenVerification: false临时关闭验证(禁止生产环境使用):

    GoogleProvider({
      clientId: env.GOOGLE_CLIENT_ID,
      clientSecret: env.GOOGLE_CLIENT_SECRET,
      idTokenVerification: false,
    })
    
  4. 清除浏览器缓存和Cookie
    清除旧会话缓存后,重新测试登录流程。


内容的提问来源于stack exchange,提问作者AR SHAH

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 14:22:02