Next.js 13中NextAuth自定义OAuth Provider如何用URL参数Code换取令牌?
问题描述
我创建了如下NextAuth自定义OAuth Provider:
{ id: "oidc", name: "OIDC", type: "oauth", authorization: { url: "https://www.auth.mywebsite.com/oauth2/authorize", params: { scope: "openid email profile aws.cognito.signin.user.admin", response_type: "code", client_id: process.env.CLIENT_ID, redirect_uri: "http://localhost:3000", identity_provider: "Google-OIDC", }, }, idToken: true, checks: ["state"], clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, },
用户通过该Provider登录后,仅跳转至首页,URL中携带code参数,但无法创建session对象,且自定义Provider未触发如下jwt回调(官方Provider可正常触发):
session: { strategy: "jwt", maxAge: 30 * 24 * 60 * 60 }, callbacks: { async jwt({ token, trigger, account, user, session }) { console.log("I am here, yes I am"); // 其余回调逻辑 } }
请问如何使用URL参数中的code换取令牌,并解决回调不触发的问题?
解决方案
一、修复Provider配置,让NextAuth自动处理code换令牌
你的自定义Provider缺少令牌交换的核心配置,导致NextAuth无法自动完成code换取令牌的流程,后续session创建和回调触发自然失效。需做以下调整:
- 添加
token字段,指定令牌交换的URL和必要参数 - 移除
authorization.params中的冗余参数:response_type、client_id、redirect_uri会由NextAuth自动处理,无需手动指定 - 确保
redirect_uri指向NextAuth的回调路径(默认是http://localhost:3000/api/auth/callback/oidc),而非首页
修改后的Provider配置:
{ id: "oidc", name: "OIDC", type: "oauth", authorization: { url: "https://www.auth.mywebsite.com/oauth2/authorize", params: { scope: "openid email profile aws.cognito.signin.user.admin", identity_provider: "Google-OIDC", }, }, // 新增令牌交换配置 token: { url: "https://www.auth.mywebsite.com/oauth2/token", params: { grant_type: "authorization_code" } }, // 若需获取用户信息,补充userinfo配置 userinfo: { url: "https://www.auth.mywebsite.com/oauth2/userInfo" }, idToken: true, checks: ["state"], clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, }
二、确保回调触发的配置正确性
- 验证主配置层级:确认
session和callbacks是NextAuth主配置的同级属性,结构如下:
export default NextAuth({ providers: [/* 你的自定义Provider */], session: { strategy: "jwt", maxAge: 30 * 24 * 60 * 60, }, callbacks: { async jwt({ token, trigger, account, user, session }) { console.log("I am here, yes I am"); // 可添加逻辑,比如将令牌存入token if (account) { token.accessToken = account.access_token; token.idToken = account.id_token; } return token; }, // 如需自定义session返回数据,实现session回调 async session({ session, token }) { session.user.accessToken = token.accessToken; return session; } }, })
- 检查环境变量有效性:确认
CLIENT_ID和CLIENT_SECRET已正确加载,无拼写错误或空值。
三、手动处理code换令牌(仅作备用方案)
若因特殊场景无法使用NextAuth自动流程,可在前端或API路由中手动发起请求换取令牌:
// 示例:前端获取URL中的code后发起请求 const urlParams = new URLSearchParams(window.location.search); const code = urlParams.get('code'); if (code) { const tokenResponse = await fetch('https://www.auth.mywebsite.com/oauth2/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': `Basic ${btoa(`${process.env.NEXT_PUBLIC_CLIENT_ID}:${process.env.NEXT_PUBLIC_CLIENT_SECRET}`)}` }, body: new URLSearchParams({ grant_type: 'authorization_code', code: code, redirect_uri: 'http://localhost:3000/api/auth/callback/oidc', client_id: process.env.NEXT_PUBLIC_CLIENT_ID }) }); const tokenData = await tokenResponse.json(); // 后续可将令牌存入存储,或调用NextAuth的signIn方法传入令牌 }
注意:优先使用NextAuth自动流程,手动处理易引发安全风险和兼容性问题。
内容的提问来源于stack exchange,提问作者Sahil Singh
相关产品推荐
相关产品推荐

