NextAuth Azure AD B2C中Access Token未定义问题(NextJS Pages TypeScript)
问题:无法获取Azure AD B2C的Access Token并附加到NextAuth Session中
我一直尝试将access token附加到session中,但无法获取access token的值,不确定自身配置是否正确。以下是我的实现代码:
import util from "node:util"; import NextAuth, { AuthOptions } from "next-auth"; import AzureADB2CProvider from "next-auth/providers/azure-ad-b2c"; export const authOptions: AuthOptions = { providers: [ AzureADB2CProvider({ tenantId: process.env.AZURE_AD_B2C_TENANT_NAME, clientId: process.env.AZURE_AD_B2C_CLIENT_ID ?? "", clientSecret: process.env.AZURE_AD_B2C_CLIENT_SECRET ?? "", primaryUserFlow: process.env.AZURE_AD_B2C_PRIMARY_USER_FLOW, authorization: { params: { scope: "offline_access openid" }, }, token: { params: { scope: "openid profile user.Read.All email" }, }, // Attach UserProfileID into the Session Profile while keeping defaults profile(profile) { return { id: profile.sub, name: profile.name, email: profile?.emails?.[0], userProfileID: profile?.extension_UserProfileID, image: null, }; }, }), ], callbacks: { async signIn({ profile }) { // It's a newly created account when extension_UserProfileID does not exist if (profile && !("extension_UserProfileID" in profile)) { return "/?newUser=1"; } else { return true; } }, async jwt({ token, user, account, profile }) { // I should get the value for access token in the account console.log("account", account); // On JWT Token, Attach id_token from account - which exists only on SignIn if (account && user) { token.id_token = account.id_token; token.userProfileID = user.userProfileID; } return token; }, async session({ session, token }) { // Expose userProfileID unto the Session if ("userProfileID" in token) { session.user.userProfileID = Number(token.userProfileID); } // Include the ID Token in the Session if ("id_token" in token) { session.user.idt = String(token.id_token ?? ""); } // To do: Dynamically load Role based on API session.user.role = "ServiceRequest"; return session; }, }, logger: { error(code, metadata) { console.error(code, metadata); }, warn(code) { console.warn(code); }, debug(code, metadata) { console.debug(code, util.inspect(metadata, true, null, true)); }, }, }; export default NextAuth(authOptions);
AD B2C中的access token配置已开启隐式授权和混合流。
控制台输出的account对象如下:
account: { provider: 'azure-ad-b2c', type: 'oauth', providerAccountId: '8e22.......', id_token: 'eyJraW.......', token_type: 'Bearer', not_before: 1705946179, id_token_expires_in: 3600, profile_info: 'eyJraW.......', scope: 'offline_access openid', refresh_token: 'eyJraW.......', refresh_token_expires_in: 86400 }
我已经尝试过相关解决方案,但问题仍未解决。
解决方案
1. 修正Scope配置,确保请求Access Token
当前配置中,authorization和token的scope未包含目标API的权限范围,Azure AD B2C仅在请求具体API权限时才会返回access token。
修改AzureADB2CProvider的scope配置:
AzureADB2CProvider({ // ...其他配置 authorization: { params: { scope: "offline_access openid https://你的租户名.onmicrosoft.com/你的API标识/API权限范围" }, }, token: { params: { scope: "offline_access openid https://你的租户名.onmicrosoft.com/你的API标识/API权限范围" }, }, // ...其他配置 })
替换示例中的API权限范围为你实际的配置(可在Azure AD B2C应用注册的API权限页获取)。
2. 在JWT回调中捕获Access Token
account对象中的access_token字段即为所需值,需将其存入token对象,再传递到session:
更新jwt回调:
async jwt({ token, user, account, profile }) { if (account && user) { token.id_token = account.id_token; token.userProfileID = user.userProfileID; // 新增:保存access token到token对象 token.access_token = account.access_token; token.access_token_expires = account.expires_at; // 可选:保存过期时间 } // 可选:处理access token过期,用refresh_token刷新 if (Date.now() < (token.access_token_expires as number) * 1000) { return token; } // 此处可添加刷新逻辑,调用NextAuth的refreshAccessToken方法 return token; }
3. 将Access Token附加到Session
更新session回调,把access token加入session:
async session({ session, token }) { if ("userProfileID" in token) { session.user.userProfileID = Number(token.userProfileID); } if ("id_token" in token) { session.user.idt = String(token.id_token ?? ""); } // 新增:将access token加入session if ("access_token" in token) { session.user.access_token = String(token.access_token ?? ""); } session.user.role = "ServiceRequest"; return session; }
4. 检查Azure AD B2C应用配置
- 确认应用注册已启用授权码流(因使用client_secret,后端服务更适合授权码流而非隐式流)
- 确保API权限已正确添加并完成管理员同意
- 验证回复URL配置与NextAuth的回调地址完全一致
内容的提问来源于stack exchange,提问作者Jedd Niñonuevo
相关产品推荐
相关产品推荐

