NextAuth v4自定义Sketchfab OAuth提供者时遇state缺失RPError
环境信息
- Next.js 13.2.4
- NextAuth 4.21.1
- 部署平台:Vercel
- 页面配置:仅域名根目录有包含
signin()按钮的登录页
自定义Provider配置代码
import NextAuth, { NextAuthOptions } from "next-auth" const SKETCHFAB_CLIENT_ID = "REDACTED" const SKETCHFAB_AUTHORIZE_URL = "https://sketchfab.com/oauth2/authorize/" export const authOptions: NextAuthOptions = { providers: [ { id: "sketchfab", name: "Sketchfab", type: "oauth", authorization: { url: SKETCHFAB_AUTHORIZE_URL, params: { scope: "read", response_type: "token", }, }, checks: ["state"], clientId: SKETCHFAB_CLIENT_ID, profile(profile, tokens) { return { id: profile.sub, name: profile.name, email: profile.email, } }, }, ], session: { strategy: "jwt", }, jwt: { secret: process.env.NEXTAUTH_SECRET, }, debug: true, } export default NextAuth(authOptions)
错误详情
从Sketchfab授权完成跳转回应用时,抛出state missing from the response错误,Vercel服务器错误日志如下:
[next-auth][error][OAUTH_CALLBACK_ERROR] https://next-auth.js.org/errors#oauth_callback_error state missing from the response { error: RPError: state missing from the response at Client.oauthCallback (/var/task/node_modules/openid-client/lib/client.js:524:13) at oAuthCallback (/var/task/node_modules/next-auth/core/lib/oauth/callback.js:111:29) at async Object.callback (/var/task/node_modules/next-auth/core/routes/callback.js:52:11) at async AuthHandler (/var/task/node_modules/next-auth/core/index.js:201:28) at async NextAuthHandler (/var/task/node_modules/next-auth/next/index.js:24:19) at async /var/task/node_modules/next-auth/next/index.js:60:32 at async Object.apiResolver (/var/task/node_modules/next/dist/server/api-utils/node.js:372:9) at async NextNodeServer.runApi (/var/task/node_modules/next/dist/server/next-server.js:514:9) at async Object.fn (/var/task/node_modules/next/dist/server/next-server.js:828:35) at async Router.execute (/var/task/node_modules/next/dist/server/router.js:243:32) { name: 'OAuthCallbackError', code: undefined }, providerId: 'sketchfab', message: 'state missing from the response' }
登录页面Debug日志
[next-auth][debug][CREATE_STATE] { value: 'Jt_U13aNxYIBiyd-uEQ9P5ECjlPzClMQkACAk-o4WYE', maxAge: 900 } [next-auth][debug][GET_AUTHORIZATION_URL] { url: 'https://sketchfab.com/oauth2/authorize/?client_id=REDACTED&scope=read&response_type=token&redirect_uri=https%3A%2F%2Fproduct-kraken.skyixd.com%2Fapi%2Fauth%2Fcallback%2Fsketchfab&state=Jt_U13aNxYIBiyd-uEQ9P5ECjlPzClMQkACAk-o4WYE', cookies: [ { name: '__Secure-next-auth.state', value: 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..Nj7ht69QuSSUvEvd.rqMbFxOxA99sHnfrGRpn7dkoC91UYe_jFfZcMqqZE4y7wVg-xfpUp5277jp7uzSdGM4YLvD1IrTDk5hyC_1yzF4cNiM-ooMjeeZt4L5L4yaND2mt2aK7oN60Y4AzcPPcAH_axVEuEer29rbTBieBNJIccvWHgPe9tZLTfmOdVhlvMi2p1J4.RorKlTuYxNLsiqxglAzgqg', options: [Object] } ], provider: { id: 'sketchfab', name: 'Sketchfab', type: 'oauth', authorization: { url: 'https://sketchfab.com/oauth2/authorize/', params: [Object] }, checks: [ 'state' ], clientId: 'REDACTED', profile: [Function: profile], idToken: false, signinUrl: 'REDACTED/api/auth/signin/sketchfab', callbackUrl: 'REDACTED/api/auth/callback/sketchfab' } }
关键观察
跳转回应用的URL中确实包含state参数,但参数位于URL的hash部分:
/api/auth/signin?error=OAuthCallback#access_token=qi7L2kbPCcm68sYsvZ8ZAIiG7h16NS&expires_in=2592000&token_type=Bearer&scope=read&state=S39Mph8lxdZzE2O7AraydXa3mMdCduJfOXkX8F5Fr6g
排查建议
修改授权请求的response_mode参数:在provider的authorization.params中添加
response_mode: "query",让Sketchfab将授权结果(包括state)放在URL的query参数而非hash中。服务器端无法读取URL hash部分的内容,这是当前错误的核心原因。修改后的authorization配置如下:authorization: { url: SKETCHFAB_AUTHORIZE_URL, params: { scope: "read", response_type: "token", response_mode: "query" }, },注意:需确认Sketchfab OAuth2服务支持
response_mode=query参数自定义客户端回调处理:如果Sketchfab不支持修改response_mode,需要在客户端处理hash参数:
- 创建自定义的回调页面(如
pages/auth/callback/sketchfab.tsx) - 在页面中用JavaScript读取URL hash中的参数,将其转换为query参数后,跳转至NextAuth的官方callback接口(
/api/auth/callback/sketchfab) - 示例代码片段:
useEffect(() => { const hash = window.location.hash.slice(1); if (hash) { const params = new URLSearchParams(hash); window.location.href = `/api/auth/callback/sketchfab?${params.toString()}`; } }, []);
- 创建自定义的回调页面(如
检查redirect_uri一致性:确认Sketchfab开发者后台配置的redirect_uri,与NextAuth中自动生成的callbackUrl(日志中显示的
callbackUrl字段)完全一致,包括协议(http/https)、域名、路径,无大小写或斜杠差异。调整state校验配置:临时尝试将
checks: ["state"]改为checks: [](仅用于排查),如果错误消失,说明问题确实出在state参数的传递环节,但不建议长期关闭校验,需优先解决参数传递问题。排查Cookie问题:检查
__Secure-next-auth.statecookie的SameSite、Domain等配置,确保在Vercel部署环境下,服务器能正常读取该cookie(可在浏览器开发者工具的Application面板查看cookie属性)。
内容的提问来源于stack exchange,提问作者user21624424

