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

如何通过Azure AD权限范围与oidc-client.js获取用户信息及访问令牌?

解决oidc-client.js同时请求自定义API范围和openid时,getUser()调用Graph userinfo端点401的问题

你遇到的核心问题其实是access_token的受众(aud字段)不匹配,这是Azure AD结合OIDC协议使用时的常见细节,我来帮你拆解清楚:

问题根源

当你在scope中同时指定自定义API范围(api://${clientId}/access_user_data)和openid时,Azure AD返回的access_token是专为你的自定义API生成的——它的受众是你的API的client ID,而非Microsoft Graph。而https://graph.microsoft.com/oidc/userinfo端点只接受受众为Graph的access_token,用自定义API的token请求自然会返回401。

单独设置scope: "openid"时,返回的token受众匹配Graph,或者id_token里已经包含足够信息,所以getUser()能正常工作,但此时你又缺失了访问自定义API的权限。

解决方案

根据你的需求,有两种可行的解决思路:

思路1:直接从id_token获取用户信息,跳过Graph userinfo端点

OIDC的openid范围要求id_token必须包含用户的基本身份信息(比如sub、name、email、preferred_username等),这些信息已经存在于user.profile中,完全不需要额外调用userinfo端点。

调整你的配置如下:

var settings: UserManagerSettings = {
  authority: `https://login.microsoftonline.com/${tenantId}`,
  client_id: clientId,
  redirect_uri: "http://localhost:3000/authcallback",
  post_logout_redirect_uri: "http://localhost:3000/authcallback",
  response_type: "token id_token",
  scope: `api://${clientId}/access_user_data openid`,
  popup_redirect_uri: "http://localhost:3000/authcallback",
  silent_redirect_uri: "http://localhost:3000/authcallback",
  automaticSilentRenew: true,
  loadUserInfo: false, // 关闭自动调用userinfo端点
  metadata: {
    authorization_endpoint: `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize`,
    issuer: `https://login.microsoftonline.com/${tenantId}/v2.0`,
    jwks_uri: `https://login.microsoftonline.com/${tenantId}/discovery/v2.0/keys`
    // 移除userinfo_endpoint配置,因为我们不再需要它
  }
};

之后调用getUser()时,直接从user.profile里拿用户信息即可:

const user = await userManager.getUser();
console.log("用户名:", user.profile.name);
console.log("邮箱:", user.profile.email);

思路2:获取两个不同的access_token(分别用于自定义API和Graph)

如果你确实需要调用Graph的userinfo端点获取更多用户信息,就得获取一个受众为Microsoft Graph的access_token。由于implicit flow一次只能返回一个token,你可以通过静默登录来获取第二个token:

  1. 先在Azure门户中给你的应用添加Microsoft Graph的User.Read委托权限,并完成管理员同意。
  2. 保留原有针对自定义API的UserManager,再新增一个专门用于Graph的实例:
// 原有针对自定义API的UserManager
const apiUserManager = new UserManager(apiSettings);

// 新增针对Graph的UserManager配置
const graphSettings: UserManagerSettings = {
  authority: `https://login.microsoftonline.com/${tenantId}`,
  client_id: clientId,
  redirect_uri: "http://localhost:3000/authcallback",
  response_type: "token",
  scope: "https://graph.microsoft.com/User.Read openid",
  silent_redirect_uri: "http://localhost:3000/authcallback",
  automaticSilentRenew: false,
  loadUserInfo: true,
  metadata: {
    userinfo_endpoint: "https://graph.microsoft.com/oidc/userinfo",
    authorization_endpoint: `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize`,
    issuer: `https://login.microsoftonline.com/${tenantId}/v2.0`,
    jwks_uri: `https://login.microsoftonline.com/${tenantId}/discovery/v2.0/keys`
  }
};
const graphUserManager = new UserManager(graphSettings);
  1. 在首次登录成功后,调用graphUserManager.signinSilent()获取Graph的token,此时再调用graphUserManager.getUser()就能正常访问userinfo端点了。

额外提示

  • 可以用jwt.ms解析token,确认aud字段是否匹配目标服务,这是排查token权限问题的常用方法。
  • 如果不需要Graph的额外信息,思路1是最简洁的方案——毕竟id_token已经包含了OIDC标准要求的所有基本用户信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 08:22:33