【问题标题】:msal.js v2.3 acquireTokenSilent returning empty access tokenmsal.js v2.3 acquireTokenSilent 返回空访问令牌
【发布时间】:2020-10-17 21:43:10
【问题描述】:

我正在将使用 msal.js v1.3 的应用升级到 v2.3,但在获得我的 id 令牌后检索访问令牌时遇到问题。

我在构造函数中初始化了 handleRedirectPromise。然后,当用户单击登录按钮时,我调用 loginRedirect 并传入一个对象,该对象具有 openid 范围和来自我单独注册的 api 的范围。这很好用,id 令牌回来了,我调用 acquireTokenSilent 来检索我的访问令牌。我通过 loginRedirect 调用将一个具有我注册的 api 范围和帐户的对象传递给此函数。

问题是来自acquireTokenSilent 的授权响应有一个空的访问令牌。令牌端点的结果如下所示:

client_info: "xx"
id_token: "xx"
not_before: 1602895189
refresh_token: "xx"
refresh_token_expires_in: 1209600
scope: ""
token_type: "Bearer"

它没有访问令牌,但它确实将令牌类型指定为Bearer 响应中没有访问令牌,看起来返回的范围属性为空。这是我的代码:

    private msalConfig: Msal.Configuration = {
        auth: {
            clientId: environment.clientID,
            authority: 'https://<tenant>.b2clogin.com/<tenant>.onmicrosoft.com/B2C_1_DefaultSignInSignUp',
            knownAuthorities: ['<tenant>.b2clogin.com'],
            navigateToLoginRequestUrl: true, 
        },
        cache: {
            cacheLocation: 'sessionStorage',
            storeAuthStateInCookie: false, 
        }
    };
    private loginRequest: Msal.RedirectRequest = {
        scopes: ['openid' ,  'offline_access', 'https://<tenant>.onmicrosoft.com/api/read' ] 
    };

    private accessTokenRequest: Msal.SilentRequest = {
        scopes:  ['https://<tenant>.onmicrosoft.com/api/read'] ,
        account: null
        
    };
 constructor() {
        const _this = this;
        this.msalInstance = new Msal.PublicClientApplication(this.msalConfig);
        this.aquireSilent = (request: Msal.SilentRequest): Promise<Msal.AuthenticationResult> => {
            return _this.msalInstance.acquireTokenSilent(request).then(
                access_token => {
                    _this.cacheExpiration(access_token.expiresOn);
                    _this.isLoggedIn$.next(true);
                    return access_token;
                },
                function (reason) {
                    console.error(reason);
                },
            );
        };

        this.msalInstance
            .handleRedirectPromise()
            .then((tokenResponse: Msal.AuthenticationResult) => {
                if (tokenResponse !== null) {
                    const id_token = tokenResponse.idToken;
                    const currentAccounts = this.msalInstance.getAllAccounts()
                    this.accessTokenRequest.account = currentAccounts[0];
                    this.aquireSilent(this.accessTokenRequest)
                } 
            })
            .catch(error => {
                console.error(error);
            });
    }

    public login() {
        this.msalInstance.loginRedirect(this.loginRequest);
    }

为什么访问令牌没有从令牌端点返回?它与返回空的范围有关吗?我尝试删除范围并输入无效条目并引发错误,因此我知道我的请求至少是有效的。另外,为了验证一下,我在 AAD 中有 2 个应用注册,一个是我为我的 spa 创建的,它有代码流,另一个是我的旧注册,我有一个暴露的 api 和范围的 api。

【问题讨论】:

  • 授权请求中没有范围,就没有获取访问令牌。
  • @JasSuri-MSFT 哪个部分是身份验证请求?我的 loginRequest 和我的 accessToken 请求参数都有范围。我是否也需要将其添加到我的 b2c 配置中?
  • 您的代码实际上看起来不错。检查浏览器开发工具中的应用程序存储(会话+本地)以查看 MSAL 是否引发错误
  • 没有错误。该请求也是有效的。上面我列出了调用 acquireTokenSilent 时调用的令牌端点的结果。那上面没有访问令牌,所以它让人相信我的原始请求或我的应用注册有问题。
  • jwt.ms 中填充的值是 id 令牌。您需要将 url 放入记事本中以查看是否也返回了访问令牌。您必须单击授予管理员同意。完全按照文档进行。

标签: azure-ad-b2c msal msal.js


【解决方案1】:

acquireTokenSilent 仅当缓存中已有该令牌的条目时才会返回访问令牌。因此,如果由于某种原因之前从未获得过令牌(例如通过loginRedirect),它将无法静默获得它。

这似乎是你的问题。您在 loginRequest 中混合了不同资源的作用域,这可能是导致新版本库出现问题的原因(访问令牌是 per-resource-per-scope(s) 发出的。请参阅这个doc 更多)尝试像这样修改你的loginRequest 对象:

  private loginRequest: Msal.RedirectRequest = {
       scopes: ['openid',  'offline_access' ],
       extraScopesToConsent:['https://<tenant>.onmicrosoft.com/api/read']

   };

此外,acquireTokenSilent 的推荐使用模式是,如果 acquireTokenSilent 由于某种原因失败,您应该退回到交互方法(例如 acquireTokenRedirect)。

所以我将其修改为:

    this.aquireSilent = (request: Msal.SilentRequest): Promise<Msal.AuthenticationResult> => {
        return _this.msalInstance.acquireTokenSilent(request).then(
            access_token => {
                 // fallback to interaction when response is null
                 if (access_token === null) {
                   return _this.msalInstance.acquireTokenRedirect(request);
                 }
                _this.cacheExpiration(access_token.expiresOn);
                _this.isLoggedIn$.next(true);
                return access_token;
            },
            function (reason) {          
               if (reason instanceof msal.InteractionRequiredAuthError) {
                  // fallback to interaction when silent call fails
                  return _this.msalInstance.acquireTokenRedirect(request);
               } else {
                  console.warn(reason);   
               }
            },
        );
    };

here讨论了一个类似的问题

【讨论】:

  • 感谢@derisen,我在代码中添加了acquireTokenRedirect 和extraScopesToConsent。 JasSuri 指出我需要在我的客户端 api 中授予管理员同意并且它有效。我不敢相信我错过了。感谢您的所有帮助!
猜你喜欢
  • 2023-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-21
  • 2013-12-01
相关资源
最近更新 更多