wangzhibo
2026-05-09 53418655c061ac26f66058253f39200aced1ab1d
1
{"version":3,"file":"bearerTokenAuthenticationPolicy.js","sourceRoot":"","sources":["../../../src/policies/bearerTokenAuthenticationPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { AccessToken, GetTokenOptions, TokenCredential } from \"@azure/core-auth\";\nimport type { AzureLogger } from \"@azure/logger\";\nimport type { PipelineRequest, PipelineResponse, SendRequest } from \"../interfaces.js\";\nimport type { PipelinePolicy } from \"../pipeline.js\";\nimport { createTokenCycler } from \"../util/tokenCycler.js\";\nimport { logger as coreLogger } from \"../log.js\";\nimport type { RestError } from \"../restError.js\";\nimport { isRestError } from \"../restError.js\";\n\n/**\n * The programmatic identifier of the bearerTokenAuthenticationPolicy.\n */\nexport const bearerTokenAuthenticationPolicyName = \"bearerTokenAuthenticationPolicy\";\n\n/**\n * Options sent to the authorizeRequest callback\n */\nexport interface AuthorizeRequestOptions {\n  /**\n   * The scopes for which the bearer token applies.\n   */\n  scopes: string[];\n  /**\n   * Function that retrieves either a cached access token or a new access token.\n   */\n  getAccessToken: (scopes: string[], options: GetTokenOptions) => Promise<AccessToken | null>;\n  /**\n   * Request that the policy is trying to fulfill.\n   */\n  request: PipelineRequest;\n  /**\n   * A logger, if one was sent through the HTTP pipeline.\n   */\n  logger?: AzureLogger;\n}\n\n/**\n * Options sent to the authorizeRequestOnChallenge callback\n */\nexport interface AuthorizeRequestOnChallengeOptions {\n  /**\n   * The scopes for which the bearer token applies.\n   */\n  scopes: string[];\n  /**\n   * Function that retrieves either a cached access token or a new access token.\n   */\n  getAccessToken: (scopes: string[], options: GetTokenOptions) => Promise<AccessToken | null>;\n  /**\n   * Request that the policy is trying to fulfill.\n   */\n  request: PipelineRequest;\n  /**\n   * Response containing the challenge.\n   */\n  response: PipelineResponse;\n  /**\n   * A logger, if one was sent through the HTTP pipeline.\n   */\n  logger?: AzureLogger;\n}\n\n/**\n * Options to override the processing of [Continuous Access Evaluation](https://learn.microsoft.com/azure/active-directory/conditional-access/concept-continuous-access-evaluation) challenges.\n */\nexport interface ChallengeCallbacks {\n  /**\n   * Allows for the authorization of the main request of this policy before it's sent.\n   */\n  authorizeRequest?(options: AuthorizeRequestOptions): Promise<void>;\n  /**\n   * Allows to handle authentication challenges and to re-authorize the request.\n   * The response containing the challenge is `options.response`.\n   * If this method returns true, the underlying request will be sent once again.\n   * The request may be modified before being sent.\n   */\n  authorizeRequestOnChallenge?(options: AuthorizeRequestOnChallengeOptions): Promise<boolean>;\n}\n\n/**\n * Options to configure the bearerTokenAuthenticationPolicy\n */\nexport interface BearerTokenAuthenticationPolicyOptions {\n  /**\n   * The TokenCredential implementation that can supply the bearer token.\n   */\n  credential?: TokenCredential;\n  /**\n   * The scopes for which the bearer token applies.\n   */\n  scopes: string | string[];\n  /**\n   * Allows for the processing of [Continuous Access Evaluation](https://learn.microsoft.com/azure/active-directory/conditional-access/concept-continuous-access-evaluation) challenges.\n   * If provided, it must contain at least the `authorizeRequestOnChallenge` method.\n   * If provided, after a request is sent, if it has a challenge, it can be processed to re-send the original request with the relevant challenge information.\n   */\n  challengeCallbacks?: ChallengeCallbacks;\n  /**\n   * A logger can be sent for debugging purposes.\n   */\n  logger?: AzureLogger;\n}\n/**\n * Try to send the given request.\n *\n * When a response is received, returns a tuple of the response received and, if the response was received\n * inside a thrown RestError, the RestError that was thrown.\n *\n * Otherwise, if an error was thrown while sending the request that did not provide an underlying response, it\n * will be rethrown.\n */\nasync function trySendRequest(\n  request: PipelineRequest,\n  next: SendRequest,\n): Promise<[PipelineResponse, RestError | undefined]> {\n  try {\n    return [await next(request), undefined];\n  } catch (e: any) {\n    if (isRestError(e) && e.response) {\n      return [e.response, e];\n    } else {\n      throw e;\n    }\n  }\n}\n/**\n * Default authorize request handler\n */\nasync function defaultAuthorizeRequest(options: AuthorizeRequestOptions): Promise<void> {\n  const { scopes, getAccessToken, request } = options;\n  // Enable CAE true by default\n  const getTokenOptions: GetTokenOptions = {\n    abortSignal: request.abortSignal,\n    tracingOptions: request.tracingOptions,\n    enableCae: true,\n  };\n\n  const accessToken = await getAccessToken(scopes, getTokenOptions);\n\n  if (accessToken) {\n    options.request.headers.set(\"Authorization\", `Bearer ${accessToken.token}`);\n  }\n}\n\n/**\n * We will retrieve the challenge only if the response status code was 401,\n * and if the response contained the header \"WWW-Authenticate\" with a non-empty value.\n */\nfunction isChallengeResponse(response: PipelineResponse): boolean {\n  return response.status === 401 && response.headers.has(\"WWW-Authenticate\");\n}\n\n/**\n * Re-authorize the request for CAE challenge.\n * The response containing the challenge is `options.response`.\n * If this method returns true, the underlying request will be sent once again.\n */\nasync function authorizeRequestOnCaeChallenge(\n  onChallengeOptions: AuthorizeRequestOnChallengeOptions,\n  caeClaims: string,\n): Promise<boolean> {\n  const { scopes } = onChallengeOptions;\n\n  const accessToken = await onChallengeOptions.getAccessToken(scopes, {\n    enableCae: true,\n    claims: caeClaims,\n  });\n  if (!accessToken) {\n    return false;\n  }\n\n  onChallengeOptions.request.headers.set(\n    \"Authorization\",\n    `${accessToken.tokenType ?? \"Bearer\"} ${accessToken.token}`,\n  );\n  return true;\n}\n\n/**\n * A policy that can request a token from a TokenCredential implementation and\n * then apply it to the Authorization header of a request as a Bearer token.\n */\nexport function bearerTokenAuthenticationPolicy(\n  options: BearerTokenAuthenticationPolicyOptions,\n): PipelinePolicy {\n  const { credential, scopes, challengeCallbacks } = options;\n  const logger = options.logger || coreLogger;\n  const callbacks = {\n    authorizeRequest:\n      challengeCallbacks?.authorizeRequest?.bind(challengeCallbacks) ?? defaultAuthorizeRequest,\n    authorizeRequestOnChallenge:\n      challengeCallbacks?.authorizeRequestOnChallenge?.bind(challengeCallbacks),\n  };\n\n  // This function encapsulates the entire process of reliably retrieving the token\n  // The options are left out of the public API until there's demand to configure this.\n  // Remember to extend `BearerTokenAuthenticationPolicyOptions` with `TokenCyclerOptions`\n  // in order to pass through the `options` object.\n  const getAccessToken = credential\n    ? createTokenCycler(credential /* , options */)\n    : () => Promise.resolve(null);\n\n  return {\n    name: bearerTokenAuthenticationPolicyName,\n    /**\n     * If there's no challenge parameter:\n     * - It will try to retrieve the token using the cache, or the credential's getToken.\n     * - Then it will try the next policy with or without the retrieved token.\n     *\n     * It uses the challenge parameters to:\n     * - Skip a first attempt to get the token from the credential if there's no cached token,\n     *   since it expects the token to be retrievable only after the challenge.\n     * - Prepare the outgoing request if the `prepareRequest` method has been provided.\n     * - Send an initial request to receive the challenge if it fails.\n     * - Process a challenge if the response contains it.\n     * - Retrieve a token with the challenge information, then re-send the request.\n     */\n    async sendRequest(request: PipelineRequest, next: SendRequest): Promise<PipelineResponse> {\n      if (!request.url.toLowerCase().startsWith(\"https://\")) {\n        throw new Error(\n          \"Bearer token authentication is not permitted for non-TLS protected (non-https) URLs.\",\n        );\n      }\n\n      await callbacks.authorizeRequest({\n        scopes: Array.isArray(scopes) ? scopes : [scopes],\n        request,\n        getAccessToken,\n        logger,\n      });\n\n      let response: PipelineResponse;\n      let error: Error | undefined;\n      let shouldSendRequest: boolean;\n      [response, error] = await trySendRequest(request, next);\n\n      if (isChallengeResponse(response)) {\n        let claims = getCaeChallengeClaims(response.headers.get(\"WWW-Authenticate\"));\n        // Handle CAE by default when receive CAE claim\n        if (claims) {\n          let parsedClaim: string;\n          // Return the response immediately if claims is not a valid base64 encoded string\n          try {\n            parsedClaim = atob(claims);\n          } catch (e) {\n            logger.warning(\n              `The WWW-Authenticate header contains \"claims\" that cannot be parsed. Unable to perform the Continuous Access Evaluation authentication flow. Unparsable claims: ${claims}`,\n            );\n            return response;\n          }\n          shouldSendRequest = await authorizeRequestOnCaeChallenge(\n            {\n              scopes: Array.isArray(scopes) ? scopes : [scopes],\n              response,\n              request,\n              getAccessToken,\n              logger,\n            },\n            parsedClaim,\n          );\n          // Send updated request and handle response for RestError\n          if (shouldSendRequest) {\n            [response, error] = await trySendRequest(request, next);\n          }\n        } else if (callbacks.authorizeRequestOnChallenge) {\n          // Handle custom challenges when client provides custom callback\n          shouldSendRequest = await callbacks.authorizeRequestOnChallenge({\n            scopes: Array.isArray(scopes) ? scopes : [scopes],\n            request,\n            response,\n            getAccessToken,\n            logger,\n          });\n\n          // Send updated request and handle response for RestError\n          if (shouldSendRequest) {\n            [response, error] = await trySendRequest(request, next);\n          }\n\n          // If we get another CAE Claim, we will handle it by default and return whatever value we receive for this\n          if (isChallengeResponse(response)) {\n            claims = getCaeChallengeClaims(response.headers.get(\"WWW-Authenticate\") as string);\n            if (claims) {\n              let parsedClaim: string;\n              try {\n                parsedClaim = atob(claims);\n              } catch (e) {\n                logger.warning(\n                  `The WWW-Authenticate header contains \"claims\" that cannot be parsed. Unable to perform the Continuous Access Evaluation authentication flow. Unparsable claims: ${claims}`,\n                );\n                return response;\n              }\n\n              shouldSendRequest = await authorizeRequestOnCaeChallenge(\n                {\n                  scopes: Array.isArray(scopes) ? scopes : [scopes],\n                  response,\n                  request,\n                  getAccessToken,\n                  logger,\n                },\n                parsedClaim,\n              );\n              // Send updated request and handle response for RestError\n              if (shouldSendRequest) {\n                [response, error] = await trySendRequest(request, next);\n              }\n            }\n          }\n        }\n      }\n\n      if (error) {\n        throw error;\n      } else {\n        return response;\n      }\n    },\n  };\n}\n\n/**\n *\n * Interface to represent a parsed challenge.\n *\n * @internal\n */\ninterface AuthChallenge {\n  scheme: string;\n  params: Record<string, string>;\n}\n\n/**\n * Converts: `Bearer a=\"b\", c=\"d\", Pop e=\"f\", g=\"h\"`.\n * Into: `[ { scheme: 'Bearer', params: { a: 'b', c: 'd' } }, { scheme: 'Pop', params: { e: 'f', g: 'h' } } ]`.\n *\n * @internal\n */\nexport function parseChallenges(challenges: string): AuthChallenge[] {\n  // Challenge regex seperates the string to individual challenges with different schemes in the format `Scheme a=\"b\", c=d`\n  // The challenge regex captures parameteres with either quotes values or unquoted values\n  const challengeRegex = /(\\w+)\\s+((?:\\w+=(?:\"[^\"]*\"|[^,]*),?\\s*)+)/g;\n  // Parameter regex captures the claims group removed from the scheme in the format `a=\"b\"` and `c=\"d\"`\n  // CAE challenge always have quoted parameters. For more reference, https://learn.microsoft.com/entra/identity-platform/claims-challenge\n  const paramRegex = /(\\w+)=\"([^\"]*)\"/g;\n\n  const parsedChallenges: AuthChallenge[] = [];\n  let match;\n\n  // Iterate over each challenge match\n  while ((match = challengeRegex.exec(challenges)) !== null) {\n    const scheme = match[1];\n    const paramsString = match[2];\n    const params: Record<string, string> = {};\n    let paramMatch;\n\n    // Iterate over each parameter match\n    while ((paramMatch = paramRegex.exec(paramsString)) !== null) {\n      params[paramMatch[1]] = paramMatch[2];\n    }\n\n    parsedChallenges.push({ scheme, params });\n  }\n  return parsedChallenges;\n}\n\n/**\n * Parse a pipeline response and look for a CAE challenge with \"Bearer\" scheme\n * Return the value in the header without parsing the challenge\n * @internal\n */\nfunction getCaeChallengeClaims(challenges: string | undefined): string | undefined {\n  if (!challenges) {\n    return;\n  }\n  // Find all challenges present in the header\n  const parsedChallenges = parseChallenges(challenges);\n  return parsedChallenges.find(\n    (x) => x.scheme === \"Bearer\" && x.params.claims && x.params.error === \"insufficient_claims\",\n  )?.params.claims;\n}\n"]}