【问题标题】:Create user access token for AAD application using Node使用 Node 为 AAD 应用程序创建用户访问令牌
【发布时间】:2021-05-02 00:51:55
【问题描述】:

对于一个测试场景,我想使用 APPLICATION_ID as aud 声明为 AAD 应用程序创建访问令牌。

我使用 Azure CLI 创建了正确的令牌(在我使用 公开 API 视图授权 Azure CLI 应用程序之后)。

$ az login -u <USERNAME> --allow-no-subscription
$ az account get-access-token --tenant <TENANT_ID> --resource <APPLICATION_ID>

我在 Node.js 中使用 @azure/ms-rest-nodeauth 尝试了类似的东西。

async function getToken(): Promise<string> {
  const credentials = await msRestNodeAuth.loginWithUsernamePassword(
    USERNAME,
    PASSWORD, {
      domain: TENANT_ID,
      tokenAudience: APPLICATION_ID,
    },
  );
  return (await credentials.getToken()).accessToken;
}

代码返回一个 Bearer 令牌,但我在使用它时得到了401。事实证明,aud 声明的设置方式与 Azure CLI 不同。节点代码以 spn: 为值添加前缀,这是 SAML 协议的记录行为(参见 Audience 部分)。

我还尝试将../oauth2/v2.0/token REST 端点与grant_type=password 一起使用,但无法获得任何令牌。

如何创建一个与 APPLICATION_ID 完全一致的用户令牌,就像 aud 声明的那样?

【问题讨论】:

  • 你检查过document中关于ROPC流程的重要吗?
  • @PamelaPeng 是的。它用于grant_type=password 方法。我收到了AADSTS50126: Error validating credentials due to invalid username or password. 作为错误消息。
  • 受邀加入 Azure AD 租户的个人帐户无法使用 ROPC。您的帐户是类似于“xxx@{tenant-name}.onmicrosoft.com”的 Azure AD 帐户吗?
  • @PamelaPeng 这不是个人帐户。它是一个 Azure AD 帐户,但由另一个 Azure AD 实例管理(来源:外部 Azure Active Directory,创建类型:邀请)。除了 ROPC 之外,是否还有其他可以通过编程方式创建用户令牌的身份验证流程?
  • 您可以在没有用户的情况下使用client credentials flow,或者在登录用户的情况下使用auth code flow。代码示例here.

标签: node.js azure azure-active-directory


【解决方案1】:

事实证明,Azure CLI 执行三个步骤来创建应用程序特定的访问令牌。

  1. 通过 SAML 验证用户凭据。
  2. 使用grant_type: 'urn:ietf:params:oauth:grant-type:saml1_1-bearer' 请求一般用户授权
  3. 使用grant_type: 'refresh_token' 请求特定于应用程序的授权

我能够通过axios 使用REST API 创建一个没有spn: 前缀的有效令牌。

async function getToken(): Promise<string> {
  const credentials = await msRestNodeAuth.loginWithUsernamePassword(
    USERNAME,
    PASSWORD, {
      domain: TENANT_ID,
    },
  );
  // Mimic Azure CLI`s 'az account get-access-token' to avoid spn: prefix
  const { refreshToken } = (await credentials.getToken());
  const resp = await axios.request<{ access_token: string }>({
    method: 'POST',
    url: `https://login.microsoftonline.com/${TENANT_ID}/oauth2/token`,
    data: qs.stringify({
      grant_type: 'refresh_token',
      client_id: credentials.clientId,
      resource: APPLICATION_ID,
      refresh_token: refreshToken,
    }),
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  });
  return resp.data.access_token;
}

【讨论】:

    【解决方案2】:

    添加我的评论作为答案:

    当使用ROPC flow(表示grant_type=password)时,我们需要当前租户的Azure AD帐户,而不是邀请帐户。您可以使用此流程创建一个测试 AD 用户以获取访问令牌。详情请见here。

    注意:Microsoft 建议您不要使用 ROPC 流程。

    如果您想在没有用户登录的情况下获取令牌,client credentials flow 会更好。

    如果您想通过登录用户获取令牌,可以使用auth code flow。但是,用户每次请求获取token时都需要登录浏览器。

    使用 ADAL 的代码示例:https://github.com/AzureAD/azure-activedirectory-library-for-nodejs/tree/master#windows-azure-active-directory-authentication-library-adal-for-nodejs


    如果您将资源指定为 {Guid},则 Audience 值将以 spn: 为前缀。您可以将GUID 替换为ID URI,看起来像“api://xxx”或“https://graph.microsoft.com”。

    类似问题:AzureAD JWT Token Audience claim prefix makes JWT Token invalid

    【讨论】:

    • 谢谢。对我来说,如何使用 auth code flow 以编程方式获取访问令牌对我来说并不明显。 adal-node 文档看起来很一般。请给点额外的提示好吗?
    • 将 MSAL.js 2.0 与 PKCE 结合使用的较新的简单方法:github.com/Azure-Samples/ms-identity-javascript-v2
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-28
    • 2015-12-28
    相关资源
    最近更新 更多