验证 Azure 广告访问令牌时签名无效,但 ID 令牌有效

Invalid signature while validating Azure ad access token, but id token works

我在使用 jwt.io 验证我的 Azure 广告访问令牌时收到无效签名。然而,我的 id 令牌验证得很好!

我已经看到并尝试了
中建议的解决方案

https://nicksnettravels.builttoroam.com/post/2017/01/24/Verifying-Azure-Active-Directory-JWT-Tokens.aspx
但都不适用于我的访问令牌。

访问和 Id 令牌是通过 Adal.js:

生成的
    var endpoints = {
        "https://graph.windows.net": "https://graph.windows.net"
    };
    var configOptions = {
        tenant: "<ad>.onmicrosoft.com", // Optional by default, it sends common
        clientId: "<app ID from azure portal>",
        postLogoutRedirectUri: window.location.origin,
        endpoints: endpoints,
    }
    window.authContext = new AuthenticationContext(configOptions);

为什么我可以验证我的 ID 令牌,而不是我的访问令牌?

请参考话题:https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/609

but if look at the Jwt.Header you will see a 'nonce'. This means you need special processing. Normal processing will fail.

因此,如果随机数包含在访问令牌中,使用 JWT.io 或 JwtSecurityToken 验证签名将不会成功。

如果其他人有无效签名错误,您应该查看此评论:https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/521#issuecomment-577400515

解决了我的配置问题。

本质上,如果您正在获取访问令牌来访问您自己的资源服务器而不是 Graph API,您的范围参数应该是 [CLIENT_ID]/.default(如果您使用访问令牌来访问图 API,您不需要自己验证令牌)

感谢@Antoine,我修复了我的代码。在这里,我将让我个人的 vue.js 插件可供其他人参考:

import { PublicClientApplication } from '@azure/msal-browser'
import { Notify } from 'quasar'

export class MsalService {
  _msal = null
  _store = null
  _loginRequest = null

  constructor (appConfig, store) {
    this._store = store
    this._msal = new PublicClientApplication(
      {
        auth: {
          clientId: appConfig.auth.clientId,
          authority: appConfig.auth.authority
        },
        cache: {
          cacheLocation: 'localStorage'
        }
      })

    this._loginRequest = {
      scopes: [`${appConfig.auth.clientId}/.default`]
    }
  }

  async handleResponse (response) {
    await this._store.dispatch('auth/setResponse', response)
    const accounts = this._msal.getAllAccounts()
    await this._store.dispatch('auth/setAccounts', accounts)

    if (accounts.length > 0) {
      this._msal.setActiveAccount(accounts[0])
      this._msal.acquireTokenSilent(this._loginRequest).then(async (accessTokenResponse) => {
        // Acquire token silent success
        // Call API with token
        // let accessToken = accessTokenResponse.accessToken;
        await this._store.dispatch('auth/setResponse', accessTokenResponse)
      }).catch((error) => {
        Notify.create({
          message: JSON.stringify(error),
          color: 'red'
        })
        // Acquire token silent failure, and send an interactive request
        if (error.errorMessage.indexOf('interaction_required') !== -1) {
          this._msal.acquireTokenPopup(this._loginRequest).then(async (accessTokenResponse) => {
            // Acquire token interactive success
            await this._store.dispatch('auth/setResponse', accessTokenResponse)
          }).catch((error) => {
            // Acquire token interactive failure
            Notify.create({
              message: JSON.stringify(error),
              color: 'red'
            })
          })
        }
      })
    }
  }

  async login () {
    // this._msal.handleRedirectPromise().then((res) => this.handleResponse(res))
    // await this._msal.loginRedirect(this._loginRequest)
    await this._msal.loginPopup(this._loginRequest).then((resp) => this.handleResponse(resp))
  }

  async logout () {
    await this._store.dispatch('auth/setAccounts', [])
    await this._msal.logout()
  }
}

// "async" is optional;
// more info on params: https://quasar.dev/quasar-cli/boot-files
export default ({
  app,
  store,
  Vue
}) => {
  const msalInstance = new MsalService(
    app.appConfig, store
  )
  Vue.prototype.$msal = msalInstance
  app.msal = msalInstance
}

PD:使用类星体框架

感谢Nan Yu I managed to get token that can be validated by any public jwt validator like jwt.io无法将我的评论放在 Nan Yu 的回答下的评论部分,因为它太长了)。

据我了解 Nan Yu 提到的 讨论 中的观点,即默认情况下 Azure AD 为 Microsoft Graph 生成令牌,并且这些令牌使用特殊的签名机制,以便无法使用 public 验证器来验证签名(jwt.ms 微软的验证器除外,它很可能知道神秘的 特殊处理 表示 :)).

要获取可以使用 public 验证器验证的不适用于 Microsoft Graph 的访问令牌,我必须:

  • 删除任何与 Microsoft Graph 相关的范围(默认情况下我只配置了一个范围 User.Read 所以在 appConfig > API 权限中删除它)
  • 为您的应用程序创建一个自定义范围(appConfig > 公开一个 API > 添加范围 ...)这个范围看起来像 api://{application-id}/scope-name
  • 在应用程序中添加刚刚创建的范围API权限(appConfig>API权限>添加api权限>我的APIs>select你的申请 > 委托权限 > 检查您的范围 > 添加权限)
  • 然后在你的 openid 客户端范围内使用这个范围,在我的例子中我有:openid offline_access {application-id}/scope-name

Note that in the openid client config newly created scope is used without api:// prefix (offline_access I have to enable refresh_token can be ignored if refresh token mechanism is not used)