@typespec/ts-http-runtime 0.1.0-alpha.20250325.2 → 0.2.0-alpha.20250326.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/auth/credentials.d.ts +77 -0
- package/dist/browser/auth/credentials.js +27 -0
- package/dist/browser/auth/credentials.js.map +1 -0
- package/dist/browser/auth/oauth2Flows.d.ts +57 -0
- package/dist/browser/{abort-controller/AbortSignalLike.js → auth/oauth2Flows.js} +1 -1
- package/dist/browser/auth/oauth2Flows.js.map +1 -0
- package/dist/browser/auth/schemes.d.ts +53 -0
- package/dist/{esm/abort-controller/AbortSignalLike.js → browser/auth/schemes.js} +1 -1
- package/dist/browser/auth/schemes.js.map +1 -0
- package/dist/browser/client/clientHelpers.d.ts +1 -20
- package/dist/browser/client/clientHelpers.js +21 -30
- package/dist/browser/client/clientHelpers.js.map +1 -1
- package/dist/browser/client/common.d.ts +13 -15
- package/dist/browser/client/common.js.map +1 -1
- package/dist/browser/client/getClient.d.ts +1 -9
- package/dist/browser/client/getClient.js +8 -16
- package/dist/browser/client/getClient.js.map +1 -1
- package/dist/browser/constants.js +1 -1
- package/dist/browser/constants.js.map +1 -1
- package/dist/browser/index.d.ts +3 -3
- package/dist/browser/index.js +2 -2
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/interfaces.d.ts +10 -2
- package/dist/browser/interfaces.js.map +1 -1
- package/dist/browser/pipelineRequest.d.ts +1 -2
- package/dist/browser/pipelineRequest.js.map +1 -1
- package/dist/browser/policies/auth/apiKeyAuthenticationPolicy.d.ts +30 -0
- package/dist/browser/policies/auth/apiKeyAuthenticationPolicy.js +31 -0
- package/dist/browser/policies/auth/apiKeyAuthenticationPolicy.js.map +1 -0
- package/dist/browser/policies/auth/basicAuthenticationPolicy.d.ts +30 -0
- package/dist/browser/policies/auth/basicAuthenticationPolicy.js +31 -0
- package/dist/browser/policies/auth/basicAuthenticationPolicy.js.map +1 -0
- package/dist/browser/policies/auth/bearerAuthenticationPolicy.d.ts +30 -0
- package/dist/browser/policies/auth/bearerAuthenticationPolicy.js +31 -0
- package/dist/browser/policies/auth/bearerAuthenticationPolicy.js.map +1 -0
- package/dist/browser/policies/auth/checkInsecureConnection.d.ts +9 -0
- package/dist/browser/policies/auth/checkInsecureConnection.js +50 -0
- package/dist/browser/policies/auth/checkInsecureConnection.js.map +1 -0
- package/dist/browser/policies/auth/oauth2AuthenticationPolicy.d.ts +31 -0
- package/dist/browser/policies/auth/oauth2AuthenticationPolicy.js +31 -0
- package/dist/browser/policies/auth/oauth2AuthenticationPolicy.js.map +1 -0
- package/dist/browser/util/aborterUtils.d.ts +3 -4
- package/dist/browser/util/aborterUtils.js.map +1 -1
- package/dist/browser/util/helpers.d.ts +1 -2
- package/dist/browser/util/helpers.js.map +1 -1
- package/dist/commonjs/auth/credentials.d.ts +77 -0
- package/dist/commonjs/auth/credentials.js +33 -0
- package/dist/commonjs/auth/credentials.js.map +1 -0
- package/dist/commonjs/auth/oauth2Flows.d.ts +57 -0
- package/dist/commonjs/{abort-controller/AbortSignalLike.js → auth/oauth2Flows.js} +1 -1
- package/dist/commonjs/auth/oauth2Flows.js.map +1 -0
- package/dist/commonjs/auth/schemes.d.ts +53 -0
- package/dist/commonjs/auth/schemes.js +5 -0
- package/dist/commonjs/auth/schemes.js.map +1 -0
- package/dist/commonjs/client/clientHelpers.d.ts +1 -20
- package/dist/commonjs/client/clientHelpers.js +21 -31
- package/dist/commonjs/client/clientHelpers.js.map +1 -1
- package/dist/commonjs/client/common.d.ts +13 -15
- package/dist/commonjs/client/common.js.map +1 -1
- package/dist/commonjs/client/getClient.d.ts +1 -9
- package/dist/commonjs/client/getClient.js +8 -16
- package/dist/commonjs/client/getClient.js.map +1 -1
- package/dist/commonjs/constants.js +1 -1
- package/dist/commonjs/constants.js.map +1 -1
- package/dist/commonjs/index.d.ts +3 -3
- package/dist/commonjs/index.js +4 -5
- package/dist/commonjs/index.js.map +1 -1
- package/dist/commonjs/interfaces.d.ts +10 -2
- package/dist/commonjs/interfaces.js.map +1 -1
- package/dist/commonjs/pipelineRequest.d.ts +1 -2
- package/dist/commonjs/pipelineRequest.js.map +1 -1
- package/dist/commonjs/policies/auth/apiKeyAuthenticationPolicy.d.ts +30 -0
- package/dist/commonjs/policies/auth/apiKeyAuthenticationPolicy.js +35 -0
- package/dist/commonjs/policies/auth/apiKeyAuthenticationPolicy.js.map +1 -0
- package/dist/commonjs/policies/auth/basicAuthenticationPolicy.d.ts +30 -0
- package/dist/commonjs/policies/auth/basicAuthenticationPolicy.js +35 -0
- package/dist/commonjs/policies/auth/basicAuthenticationPolicy.js.map +1 -0
- package/dist/commonjs/policies/auth/bearerAuthenticationPolicy.d.ts +30 -0
- package/dist/commonjs/policies/auth/bearerAuthenticationPolicy.js +35 -0
- package/dist/commonjs/policies/auth/bearerAuthenticationPolicy.js.map +1 -0
- package/dist/commonjs/policies/auth/checkInsecureConnection.d.ts +9 -0
- package/dist/commonjs/policies/auth/checkInsecureConnection.js +53 -0
- package/dist/commonjs/policies/auth/checkInsecureConnection.js.map +1 -0
- package/dist/commonjs/policies/auth/oauth2AuthenticationPolicy.d.ts +31 -0
- package/dist/commonjs/policies/auth/oauth2AuthenticationPolicy.js +35 -0
- package/dist/commonjs/policies/auth/oauth2AuthenticationPolicy.js.map +1 -0
- package/dist/commonjs/util/aborterUtils.d.ts +3 -4
- package/dist/commonjs/util/aborterUtils.js.map +1 -1
- package/dist/commonjs/util/helpers.d.ts +1 -2
- package/dist/commonjs/util/helpers.js.map +1 -1
- package/dist/esm/auth/credentials.d.ts +77 -0
- package/dist/esm/auth/credentials.js +27 -0
- package/dist/esm/auth/credentials.js.map +1 -0
- package/dist/esm/auth/oauth2Flows.d.ts +57 -0
- package/dist/{react-native/abort-controller/AbortSignalLike.js → esm/auth/oauth2Flows.js} +1 -1
- package/dist/esm/auth/oauth2Flows.js.map +1 -0
- package/dist/esm/auth/schemes.d.ts +53 -0
- package/dist/esm/auth/schemes.js +4 -0
- package/dist/esm/auth/schemes.js.map +1 -0
- package/dist/esm/client/clientHelpers.d.ts +1 -20
- package/dist/esm/client/clientHelpers.js +21 -30
- package/dist/esm/client/clientHelpers.js.map +1 -1
- package/dist/esm/client/common.d.ts +13 -15
- package/dist/esm/client/common.js.map +1 -1
- package/dist/esm/client/getClient.d.ts +1 -9
- package/dist/esm/client/getClient.js +8 -16
- package/dist/esm/client/getClient.js.map +1 -1
- package/dist/esm/constants.js +1 -1
- package/dist/esm/constants.js.map +1 -1
- package/dist/esm/index.d.ts +3 -3
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/interfaces.d.ts +10 -2
- package/dist/esm/interfaces.js.map +1 -1
- package/dist/esm/pipelineRequest.d.ts +1 -2
- package/dist/esm/pipelineRequest.js.map +1 -1
- package/dist/esm/policies/auth/apiKeyAuthenticationPolicy.d.ts +30 -0
- package/dist/esm/policies/auth/apiKeyAuthenticationPolicy.js +31 -0
- package/dist/esm/policies/auth/apiKeyAuthenticationPolicy.js.map +1 -0
- package/dist/esm/policies/auth/basicAuthenticationPolicy.d.ts +30 -0
- package/dist/esm/policies/auth/basicAuthenticationPolicy.js +31 -0
- package/dist/esm/policies/auth/basicAuthenticationPolicy.js.map +1 -0
- package/dist/esm/policies/auth/bearerAuthenticationPolicy.d.ts +30 -0
- package/dist/esm/policies/auth/bearerAuthenticationPolicy.js +31 -0
- package/dist/esm/policies/auth/bearerAuthenticationPolicy.js.map +1 -0
- package/dist/esm/policies/auth/checkInsecureConnection.d.ts +9 -0
- package/dist/esm/policies/auth/checkInsecureConnection.js +50 -0
- package/dist/esm/policies/auth/checkInsecureConnection.js.map +1 -0
- package/dist/esm/policies/auth/oauth2AuthenticationPolicy.d.ts +31 -0
- package/dist/esm/policies/auth/oauth2AuthenticationPolicy.js +31 -0
- package/dist/esm/policies/auth/oauth2AuthenticationPolicy.js.map +1 -0
- package/dist/esm/util/aborterUtils.d.ts +3 -4
- package/dist/esm/util/aborterUtils.js.map +1 -1
- package/dist/esm/util/helpers.d.ts +1 -2
- package/dist/esm/util/helpers.js.map +1 -1
- package/dist/react-native/auth/credentials.d.ts +77 -0
- package/dist/react-native/auth/credentials.js +27 -0
- package/dist/react-native/auth/credentials.js.map +1 -0
- package/dist/react-native/auth/oauth2Flows.d.ts +57 -0
- package/dist/react-native/auth/oauth2Flows.js +4 -0
- package/dist/react-native/auth/oauth2Flows.js.map +1 -0
- package/dist/react-native/auth/schemes.d.ts +53 -0
- package/dist/react-native/auth/schemes.js +4 -0
- package/dist/react-native/auth/schemes.js.map +1 -0
- package/dist/react-native/client/clientHelpers.d.ts +1 -20
- package/dist/react-native/client/clientHelpers.js +21 -30
- package/dist/react-native/client/clientHelpers.js.map +1 -1
- package/dist/react-native/client/common.d.ts +13 -15
- package/dist/react-native/client/common.js.map +1 -1
- package/dist/react-native/client/getClient.d.ts +1 -9
- package/dist/react-native/client/getClient.js +8 -16
- package/dist/react-native/client/getClient.js.map +1 -1
- package/dist/react-native/constants.js +1 -1
- package/dist/react-native/constants.js.map +1 -1
- package/dist/react-native/index.d.ts +3 -3
- package/dist/react-native/index.js +2 -2
- package/dist/react-native/index.js.map +1 -1
- package/dist/react-native/interfaces.d.ts +10 -2
- package/dist/react-native/interfaces.js.map +1 -1
- package/dist/react-native/pipelineRequest.d.ts +1 -2
- package/dist/react-native/pipelineRequest.js.map +1 -1
- package/dist/react-native/policies/auth/apiKeyAuthenticationPolicy.d.ts +30 -0
- package/dist/react-native/policies/auth/apiKeyAuthenticationPolicy.js +31 -0
- package/dist/react-native/policies/auth/apiKeyAuthenticationPolicy.js.map +1 -0
- package/dist/react-native/policies/auth/basicAuthenticationPolicy.d.ts +30 -0
- package/dist/react-native/policies/auth/basicAuthenticationPolicy.js +31 -0
- package/dist/react-native/policies/auth/basicAuthenticationPolicy.js.map +1 -0
- package/dist/react-native/policies/auth/bearerAuthenticationPolicy.d.ts +30 -0
- package/dist/react-native/policies/auth/bearerAuthenticationPolicy.js +31 -0
- package/dist/react-native/policies/auth/bearerAuthenticationPolicy.js.map +1 -0
- package/dist/react-native/policies/auth/checkInsecureConnection.d.ts +9 -0
- package/dist/react-native/policies/auth/checkInsecureConnection.js +50 -0
- package/dist/react-native/policies/auth/checkInsecureConnection.js.map +1 -0
- package/dist/react-native/policies/auth/oauth2AuthenticationPolicy.d.ts +31 -0
- package/dist/react-native/policies/auth/oauth2AuthenticationPolicy.js +31 -0
- package/dist/react-native/policies/auth/oauth2AuthenticationPolicy.js.map +1 -0
- package/dist/react-native/util/aborterUtils.d.ts +3 -4
- package/dist/react-native/util/aborterUtils.js.map +1 -1
- package/dist/react-native/util/helpers.d.ts +1 -2
- package/dist/react-native/util/helpers.js.map +1 -1
- package/package.json +1 -1
- package/dist/browser/abort-controller/AbortSignalLike.d.ts +0 -19
- package/dist/browser/abort-controller/AbortSignalLike.js.map +0 -1
- package/dist/browser/accessTokenCache.d.ts +0 -40
- package/dist/browser/accessTokenCache.js +0 -32
- package/dist/browser/accessTokenCache.js.map +0 -1
- package/dist/browser/auth/keyCredential.d.ts +0 -16
- package/dist/browser/auth/keyCredential.js +0 -12
- package/dist/browser/auth/keyCredential.js.map +0 -1
- package/dist/browser/auth/tokenCredential.d.ts +0 -71
- package/dist/browser/auth/tokenCredential.js +0 -19
- package/dist/browser/auth/tokenCredential.js.map +0 -1
- package/dist/browser/client/keyCredentialAuthenticationPolicy.d.ts +0 -8
- package/dist/browser/client/keyCredentialAuthenticationPolicy.js +0 -16
- package/dist/browser/client/keyCredentialAuthenticationPolicy.js.map +0 -1
- package/dist/browser/policies/bearerTokenAuthenticationPolicy.d.ts +0 -99
- package/dist/browser/policies/bearerTokenAuthenticationPolicy.js +0 -107
- package/dist/browser/policies/bearerTokenAuthenticationPolicy.js.map +0 -1
- package/dist/browser/util/tokenCycler.d.ts +0 -45
- package/dist/browser/util/tokenCycler.js +0 -162
- package/dist/browser/util/tokenCycler.js.map +0 -1
- package/dist/commonjs/abort-controller/AbortSignalLike.d.ts +0 -19
- package/dist/commonjs/abort-controller/AbortSignalLike.js.map +0 -1
- package/dist/commonjs/accessTokenCache.d.ts +0 -40
- package/dist/commonjs/accessTokenCache.js +0 -36
- package/dist/commonjs/accessTokenCache.js.map +0 -1
- package/dist/commonjs/auth/keyCredential.d.ts +0 -16
- package/dist/commonjs/auth/keyCredential.js +0 -15
- package/dist/commonjs/auth/keyCredential.js.map +0 -1
- package/dist/commonjs/auth/tokenCredential.d.ts +0 -71
- package/dist/commonjs/auth/tokenCredential.js +0 -22
- package/dist/commonjs/auth/tokenCredential.js.map +0 -1
- package/dist/commonjs/client/keyCredentialAuthenticationPolicy.d.ts +0 -8
- package/dist/commonjs/client/keyCredentialAuthenticationPolicy.js +0 -20
- package/dist/commonjs/client/keyCredentialAuthenticationPolicy.js.map +0 -1
- package/dist/commonjs/policies/bearerTokenAuthenticationPolicy.d.ts +0 -99
- package/dist/commonjs/policies/bearerTokenAuthenticationPolicy.js +0 -111
- package/dist/commonjs/policies/bearerTokenAuthenticationPolicy.js.map +0 -1
- package/dist/commonjs/util/tokenCycler.d.ts +0 -45
- package/dist/commonjs/util/tokenCycler.js +0 -166
- package/dist/commonjs/util/tokenCycler.js.map +0 -1
- package/dist/esm/abort-controller/AbortSignalLike.d.ts +0 -19
- package/dist/esm/abort-controller/AbortSignalLike.js.map +0 -1
- package/dist/esm/accessTokenCache.d.ts +0 -40
- package/dist/esm/accessTokenCache.js +0 -32
- package/dist/esm/accessTokenCache.js.map +0 -1
- package/dist/esm/auth/keyCredential.d.ts +0 -16
- package/dist/esm/auth/keyCredential.js +0 -12
- package/dist/esm/auth/keyCredential.js.map +0 -1
- package/dist/esm/auth/tokenCredential.d.ts +0 -71
- package/dist/esm/auth/tokenCredential.js +0 -19
- package/dist/esm/auth/tokenCredential.js.map +0 -1
- package/dist/esm/client/keyCredentialAuthenticationPolicy.d.ts +0 -8
- package/dist/esm/client/keyCredentialAuthenticationPolicy.js +0 -16
- package/dist/esm/client/keyCredentialAuthenticationPolicy.js.map +0 -1
- package/dist/esm/policies/bearerTokenAuthenticationPolicy.d.ts +0 -99
- package/dist/esm/policies/bearerTokenAuthenticationPolicy.js +0 -107
- package/dist/esm/policies/bearerTokenAuthenticationPolicy.js.map +0 -1
- package/dist/esm/util/tokenCycler.d.ts +0 -45
- package/dist/esm/util/tokenCycler.js +0 -162
- package/dist/esm/util/tokenCycler.js.map +0 -1
- package/dist/react-native/abort-controller/AbortSignalLike.d.ts +0 -19
- package/dist/react-native/abort-controller/AbortSignalLike.js.map +0 -1
- package/dist/react-native/accessTokenCache.d.ts +0 -40
- package/dist/react-native/accessTokenCache.js +0 -32
- package/dist/react-native/accessTokenCache.js.map +0 -1
- package/dist/react-native/auth/keyCredential.d.ts +0 -16
- package/dist/react-native/auth/keyCredential.js +0 -12
- package/dist/react-native/auth/keyCredential.js.map +0 -1
- package/dist/react-native/auth/tokenCredential.d.ts +0 -71
- package/dist/react-native/auth/tokenCredential.js +0 -19
- package/dist/react-native/auth/tokenCredential.js.map +0 -1
- package/dist/react-native/client/keyCredentialAuthenticationPolicy.d.ts +0 -8
- package/dist/react-native/client/keyCredentialAuthenticationPolicy.js +0 -16
- package/dist/react-native/client/keyCredentialAuthenticationPolicy.js.map +0 -1
- package/dist/react-native/policies/bearerTokenAuthenticationPolicy.d.ts +0 -99
- package/dist/react-native/policies/bearerTokenAuthenticationPolicy.js +0 -107
- package/dist/react-native/policies/bearerTokenAuthenticationPolicy.js.map +0 -1
- package/dist/react-native/util/tokenCycler.d.ts +0 -45
- package/dist/react-native/util/tokenCycler.js +0 -162
- package/dist/react-native/util/tokenCycler.js.map +0 -1
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Microsoft Corporation.
|
|
2
|
-
// Licensed under the MIT License.
|
|
3
|
-
import { createTokenCycler } from "../util/tokenCycler.js";
|
|
4
|
-
import { logger as coreLogger } from "../log.js";
|
|
5
|
-
/**
|
|
6
|
-
* The programmatic identifier of the bearerTokenAuthenticationPolicy.
|
|
7
|
-
*/
|
|
8
|
-
export const bearerTokenAuthenticationPolicyName = "bearerTokenAuthenticationPolicy";
|
|
9
|
-
/**
|
|
10
|
-
* Default authorize request handler
|
|
11
|
-
*/
|
|
12
|
-
async function defaultAuthorizeRequest(options) {
|
|
13
|
-
const { scopes, getAccessToken, request } = options;
|
|
14
|
-
const getTokenOptions = {
|
|
15
|
-
abortSignal: request.abortSignal,
|
|
16
|
-
};
|
|
17
|
-
const accessToken = await getAccessToken(scopes, getTokenOptions);
|
|
18
|
-
if (accessToken) {
|
|
19
|
-
options.request.headers.set("Authorization", `Bearer ${accessToken.token}`);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* We will retrieve the challenge only if the response status code was 401,
|
|
24
|
-
* and if the response contained the header "WWW-Authenticate" with a non-empty value.
|
|
25
|
-
*/
|
|
26
|
-
function getChallenge(response) {
|
|
27
|
-
const challenge = response.headers.get("WWW-Authenticate");
|
|
28
|
-
if (response.status === 401 && challenge) {
|
|
29
|
-
return challenge;
|
|
30
|
-
}
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* A policy that can request a token from a TokenCredential implementation and
|
|
35
|
-
* then apply it to the Authorization header of a request as a Bearer token.
|
|
36
|
-
*/
|
|
37
|
-
export function bearerTokenAuthenticationPolicy(options) {
|
|
38
|
-
var _a;
|
|
39
|
-
const { credential, scopes, challengeCallbacks } = options;
|
|
40
|
-
const logger = options.logger || coreLogger;
|
|
41
|
-
const callbacks = Object.assign({ authorizeRequest: (_a = challengeCallbacks === null || challengeCallbacks === void 0 ? void 0 : challengeCallbacks.authorizeRequest) !== null && _a !== void 0 ? _a : defaultAuthorizeRequest, authorizeRequestOnChallenge: challengeCallbacks === null || challengeCallbacks === void 0 ? void 0 : challengeCallbacks.authorizeRequestOnChallenge }, challengeCallbacks);
|
|
42
|
-
// This function encapsulates the entire process of reliably retrieving the token
|
|
43
|
-
// The options are left out of the public API until there's demand to configure this.
|
|
44
|
-
// Remember to extend `BearerTokenAuthenticationPolicyOptions` with `TokenCyclerOptions`
|
|
45
|
-
// in order to pass through the `options` object.
|
|
46
|
-
const getAccessToken = credential
|
|
47
|
-
? createTokenCycler(credential /* , options */)
|
|
48
|
-
: () => Promise.resolve(null);
|
|
49
|
-
return {
|
|
50
|
-
name: bearerTokenAuthenticationPolicyName,
|
|
51
|
-
/**
|
|
52
|
-
* If there's no challenge parameter:
|
|
53
|
-
* - It will try to retrieve the token using the cache, or the credential's getToken.
|
|
54
|
-
* - Then it will try the next policy with or without the retrieved token.
|
|
55
|
-
*
|
|
56
|
-
* It uses the challenge parameters to:
|
|
57
|
-
* - Skip a first attempt to get the token from the credential if there's no cached token,
|
|
58
|
-
* since it expects the token to be retrievable only after the challenge.
|
|
59
|
-
* - Prepare the outgoing request if the `prepareRequest` method has been provided.
|
|
60
|
-
* - Send an initial request to receive the challenge if it fails.
|
|
61
|
-
* - Process a challenge if the response contains it.
|
|
62
|
-
* - Retrieve a token with the challenge information, then re-send the request.
|
|
63
|
-
*/
|
|
64
|
-
async sendRequest(request, next) {
|
|
65
|
-
if (!request.url.toLowerCase().startsWith("https://")) {
|
|
66
|
-
throw new Error("Bearer token authentication is not permitted for non-TLS protected (non-https) URLs.");
|
|
67
|
-
}
|
|
68
|
-
await callbacks.authorizeRequest({
|
|
69
|
-
scopes: Array.isArray(scopes) ? scopes : [scopes],
|
|
70
|
-
request,
|
|
71
|
-
getAccessToken,
|
|
72
|
-
logger,
|
|
73
|
-
});
|
|
74
|
-
let response;
|
|
75
|
-
let error;
|
|
76
|
-
try {
|
|
77
|
-
response = await next(request);
|
|
78
|
-
}
|
|
79
|
-
catch (err) {
|
|
80
|
-
error = err;
|
|
81
|
-
response = err.response;
|
|
82
|
-
}
|
|
83
|
-
if (callbacks.authorizeRequestOnChallenge &&
|
|
84
|
-
(response === null || response === void 0 ? void 0 : response.status) === 401 &&
|
|
85
|
-
getChallenge(response)) {
|
|
86
|
-
// processes challenge
|
|
87
|
-
const shouldSendRequest = await callbacks.authorizeRequestOnChallenge({
|
|
88
|
-
scopes: Array.isArray(scopes) ? scopes : [scopes],
|
|
89
|
-
request,
|
|
90
|
-
response,
|
|
91
|
-
getAccessToken,
|
|
92
|
-
logger,
|
|
93
|
-
});
|
|
94
|
-
if (shouldSendRequest) {
|
|
95
|
-
return next(request);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
if (error) {
|
|
99
|
-
throw error;
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
return response;
|
|
103
|
-
}
|
|
104
|
-
},
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
//# sourceMappingURL=bearerTokenAuthenticationPolicy.js.map
|
|
@@ -1 +0,0 @@
|
|
|
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 \"../auth/tokenCredential.js\";\nimport type { TypeSpecRuntimeLogger } from \"../logger/logger.js\";\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\";\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?: TypeSpecRuntimeLogger;\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?: TypeSpecRuntimeLogger;\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?: TypeSpecRuntimeLogger;\n}\n\n/**\n * Default authorize request handler\n */\nasync function defaultAuthorizeRequest(options: AuthorizeRequestOptions): Promise<void> {\n const { scopes, getAccessToken, request } = options;\n const getTokenOptions: GetTokenOptions = {\n abortSignal: request.abortSignal,\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 getChallenge(response: PipelineResponse): string | undefined {\n const challenge = response.headers.get(\"WWW-Authenticate\");\n if (response.status === 401 && challenge) {\n return challenge;\n }\n return;\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: challengeCallbacks?.authorizeRequest ?? defaultAuthorizeRequest,\n authorizeRequestOnChallenge: challengeCallbacks?.authorizeRequestOnChallenge,\n // keep all other properties\n ...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 try {\n response = await next(request);\n } catch (err: any) {\n error = err;\n response = err.response;\n }\n\n if (\n callbacks.authorizeRequestOnChallenge &&\n response?.status === 401 &&\n getChallenge(response)\n ) {\n // processes challenge\n const shouldSendRequest = await callbacks.authorizeRequestOnChallenge({\n scopes: Array.isArray(scopes) ? scopes : [scopes],\n request,\n response,\n getAccessToken,\n logger,\n });\n\n if (shouldSendRequest) {\n return next(request);\n }\n }\n\n if (error) {\n throw error;\n } else {\n return response;\n }\n },\n };\n}\n"]}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type { AccessToken, GetTokenOptions, TokenCredential } from "../auth/tokenCredential.js";
|
|
2
|
-
/**
|
|
3
|
-
* A function that gets a promise of an access token and allows providing
|
|
4
|
-
* options.
|
|
5
|
-
*
|
|
6
|
-
* @param options - the options to pass to the underlying token provider
|
|
7
|
-
*/
|
|
8
|
-
export type AccessTokenGetter = (scopes: string | string[], options: GetTokenOptions) => Promise<AccessToken>;
|
|
9
|
-
export interface TokenCyclerOptions {
|
|
10
|
-
/**
|
|
11
|
-
* The window of time before token expiration during which the token will be
|
|
12
|
-
* considered unusable due to risk of the token expiring before sending the
|
|
13
|
-
* request.
|
|
14
|
-
*
|
|
15
|
-
* This will only become meaningful if the refresh fails for over
|
|
16
|
-
* (refreshWindow - forcedRefreshWindow) milliseconds.
|
|
17
|
-
*/
|
|
18
|
-
forcedRefreshWindowInMs: number;
|
|
19
|
-
/**
|
|
20
|
-
* Interval in milliseconds to retry failed token refreshes.
|
|
21
|
-
*/
|
|
22
|
-
retryIntervalInMs: number;
|
|
23
|
-
/**
|
|
24
|
-
* The window of time before token expiration during which
|
|
25
|
-
* we will attempt to refresh the token.
|
|
26
|
-
*/
|
|
27
|
-
refreshWindowInMs: number;
|
|
28
|
-
}
|
|
29
|
-
export declare const DEFAULT_CYCLER_OPTIONS: TokenCyclerOptions;
|
|
30
|
-
/**
|
|
31
|
-
* Creates a token cycler from a credential, scopes, and optional settings.
|
|
32
|
-
*
|
|
33
|
-
* A token cycler represents a way to reliably retrieve a valid access token
|
|
34
|
-
* from a TokenCredential. It will handle initializing the token, refreshing it
|
|
35
|
-
* when it nears expiration, and synchronizes refresh attempts to avoid
|
|
36
|
-
* concurrency hazards.
|
|
37
|
-
*
|
|
38
|
-
* @param credential - the underlying TokenCredential that provides the access
|
|
39
|
-
* token
|
|
40
|
-
* @param tokenCyclerOptions - optionally override default settings for the cycler
|
|
41
|
-
*
|
|
42
|
-
* @returns - a function that reliably produces a valid access token
|
|
43
|
-
*/
|
|
44
|
-
export declare function createTokenCycler(credential: TokenCredential, tokenCyclerOptions?: Partial<TokenCyclerOptions>): AccessTokenGetter;
|
|
45
|
-
//# sourceMappingURL=tokenCycler.d.ts.map
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Microsoft Corporation.
|
|
2
|
-
// Licensed under the MIT License.
|
|
3
|
-
import { delay } from "./helpers.js";
|
|
4
|
-
// Default options for the cycler if none are provided
|
|
5
|
-
export const DEFAULT_CYCLER_OPTIONS = {
|
|
6
|
-
forcedRefreshWindowInMs: 1000, // Force waiting for a refresh 1s before the token expires
|
|
7
|
-
retryIntervalInMs: 3000, // Allow refresh attempts every 3s
|
|
8
|
-
refreshWindowInMs: 1000 * 60 * 2, // Start refreshing 2m before expiry
|
|
9
|
-
};
|
|
10
|
-
/**
|
|
11
|
-
* Converts an an unreliable access token getter (which may resolve with null)
|
|
12
|
-
* into an AccessTokenGetter by retrying the unreliable getter in a regular
|
|
13
|
-
* interval.
|
|
14
|
-
*
|
|
15
|
-
* @param getAccessToken - A function that produces a promise of an access token that may fail by returning null.
|
|
16
|
-
* @param retryIntervalInMs - The time (in milliseconds) to wait between retry attempts.
|
|
17
|
-
* @param refreshTimeout - The timestamp after which the refresh attempt will fail, throwing an exception.
|
|
18
|
-
* @returns - A promise that, if it resolves, will resolve with an access token.
|
|
19
|
-
*/
|
|
20
|
-
async function beginRefresh(getAccessToken, retryIntervalInMs, refreshTimeout) {
|
|
21
|
-
// This wrapper handles exceptions gracefully as long as we haven't exceeded
|
|
22
|
-
// the timeout.
|
|
23
|
-
async function tryGetAccessToken() {
|
|
24
|
-
if (Date.now() < refreshTimeout) {
|
|
25
|
-
try {
|
|
26
|
-
return await getAccessToken();
|
|
27
|
-
}
|
|
28
|
-
catch (_a) {
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
const finalToken = await getAccessToken();
|
|
34
|
-
// Timeout is up, so throw if it's still null
|
|
35
|
-
if (finalToken === null) {
|
|
36
|
-
throw new Error("Failed to refresh access token.");
|
|
37
|
-
}
|
|
38
|
-
return finalToken;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
let token = await tryGetAccessToken();
|
|
42
|
-
while (token === null) {
|
|
43
|
-
await delay(retryIntervalInMs);
|
|
44
|
-
token = await tryGetAccessToken();
|
|
45
|
-
}
|
|
46
|
-
return token;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Creates a token cycler from a credential, scopes, and optional settings.
|
|
50
|
-
*
|
|
51
|
-
* A token cycler represents a way to reliably retrieve a valid access token
|
|
52
|
-
* from a TokenCredential. It will handle initializing the token, refreshing it
|
|
53
|
-
* when it nears expiration, and synchronizes refresh attempts to avoid
|
|
54
|
-
* concurrency hazards.
|
|
55
|
-
*
|
|
56
|
-
* @param credential - the underlying TokenCredential that provides the access
|
|
57
|
-
* token
|
|
58
|
-
* @param tokenCyclerOptions - optionally override default settings for the cycler
|
|
59
|
-
*
|
|
60
|
-
* @returns - a function that reliably produces a valid access token
|
|
61
|
-
*/
|
|
62
|
-
export function createTokenCycler(credential, tokenCyclerOptions) {
|
|
63
|
-
let refreshWorker = null;
|
|
64
|
-
let token = null;
|
|
65
|
-
let tenantId;
|
|
66
|
-
const options = Object.assign(Object.assign({}, DEFAULT_CYCLER_OPTIONS), tokenCyclerOptions);
|
|
67
|
-
/**
|
|
68
|
-
* This little holder defines several predicates that we use to construct
|
|
69
|
-
* the rules of refreshing the token.
|
|
70
|
-
*/
|
|
71
|
-
const cycler = {
|
|
72
|
-
/**
|
|
73
|
-
* Produces true if a refresh job is currently in progress.
|
|
74
|
-
*/
|
|
75
|
-
get isRefreshing() {
|
|
76
|
-
return refreshWorker !== null;
|
|
77
|
-
},
|
|
78
|
-
/**
|
|
79
|
-
* Produces true if the cycler SHOULD refresh (we are within the refresh
|
|
80
|
-
* window and not already refreshing)
|
|
81
|
-
*/
|
|
82
|
-
get shouldRefresh() {
|
|
83
|
-
var _a;
|
|
84
|
-
if (cycler.isRefreshing) {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
if ((token === null || token === void 0 ? void 0 : token.refreshAfterTimestamp) && token.refreshAfterTimestamp < Date.now()) {
|
|
88
|
-
return true;
|
|
89
|
-
}
|
|
90
|
-
return ((_a = token === null || token === void 0 ? void 0 : token.expiresOnTimestamp) !== null && _a !== void 0 ? _a : 0) - options.refreshWindowInMs < Date.now();
|
|
91
|
-
},
|
|
92
|
-
/**
|
|
93
|
-
* Produces true if the cycler MUST refresh (null or nearly-expired
|
|
94
|
-
* token).
|
|
95
|
-
*/
|
|
96
|
-
get mustRefresh() {
|
|
97
|
-
return (token === null || token.expiresOnTimestamp - options.forcedRefreshWindowInMs < Date.now());
|
|
98
|
-
},
|
|
99
|
-
};
|
|
100
|
-
/**
|
|
101
|
-
* Starts a refresh job or returns the existing job if one is already
|
|
102
|
-
* running.
|
|
103
|
-
*/
|
|
104
|
-
function refresh(scopes, getTokenOptions) {
|
|
105
|
-
var _a;
|
|
106
|
-
if (!cycler.isRefreshing) {
|
|
107
|
-
// We bind `scopes` here to avoid passing it around a lot
|
|
108
|
-
const tryGetAccessToken = () => credential.getToken(scopes, getTokenOptions);
|
|
109
|
-
// Take advantage of promise chaining to insert an assignment to `token`
|
|
110
|
-
// before the refresh can be considered done.
|
|
111
|
-
refreshWorker = beginRefresh(tryGetAccessToken, options.retryIntervalInMs,
|
|
112
|
-
// If we don't have a token, then we should timeout immediately
|
|
113
|
-
(_a = token === null || token === void 0 ? void 0 : token.expiresOnTimestamp) !== null && _a !== void 0 ? _a : Date.now())
|
|
114
|
-
.then((_token) => {
|
|
115
|
-
refreshWorker = null;
|
|
116
|
-
token = _token;
|
|
117
|
-
tenantId = getTokenOptions.tenantId;
|
|
118
|
-
return token;
|
|
119
|
-
})
|
|
120
|
-
.catch((reason) => {
|
|
121
|
-
// We also should reset the refresher if we enter a failed state. All
|
|
122
|
-
// existing awaiters will throw, but subsequent requests will start a
|
|
123
|
-
// new retry chain.
|
|
124
|
-
refreshWorker = null;
|
|
125
|
-
token = null;
|
|
126
|
-
tenantId = undefined;
|
|
127
|
-
throw reason;
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
return refreshWorker;
|
|
131
|
-
}
|
|
132
|
-
return async (scopes, tokenOptions) => {
|
|
133
|
-
//
|
|
134
|
-
// Simple rules:
|
|
135
|
-
// - If we MUST refresh, then return the refresh task, blocking
|
|
136
|
-
// the pipeline until a token is available.
|
|
137
|
-
// - If we SHOULD refresh, then run refresh but don't return it
|
|
138
|
-
// (we can still use the cached token).
|
|
139
|
-
// - Return the token, since it's fine if we didn't return in
|
|
140
|
-
// step 1.
|
|
141
|
-
//
|
|
142
|
-
const hasClaimChallenge = Boolean(tokenOptions.claims);
|
|
143
|
-
const tenantIdChanged = tenantId !== tokenOptions.tenantId;
|
|
144
|
-
if (hasClaimChallenge) {
|
|
145
|
-
// If we've received a claim, we know the existing token isn't valid
|
|
146
|
-
// We want to clear it so that that refresh worker won't use the old expiration time as a timeout
|
|
147
|
-
token = null;
|
|
148
|
-
}
|
|
149
|
-
// If the tenantId passed in token options is different to the one we have
|
|
150
|
-
// Or if we are in claim challenge and the token was rejected and a new access token need to be issued, we need to
|
|
151
|
-
// refresh the token with the new tenantId or token.
|
|
152
|
-
const mustRefresh = tenantIdChanged || hasClaimChallenge || cycler.mustRefresh;
|
|
153
|
-
if (mustRefresh) {
|
|
154
|
-
return refresh(scopes, tokenOptions);
|
|
155
|
-
}
|
|
156
|
-
if (cycler.shouldRefresh) {
|
|
157
|
-
refresh(scopes, tokenOptions);
|
|
158
|
-
}
|
|
159
|
-
return token;
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
//# sourceMappingURL=tokenCycler.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tokenCycler.js","sourceRoot":"","sources":["../../../src/util/tokenCycler.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 \"../auth/tokenCredential.js\";\nimport { delay } from \"./helpers.js\";\n\n/**\n * A function that gets a promise of an access token and allows providing\n * options.\n *\n * @param options - the options to pass to the underlying token provider\n */\nexport type AccessTokenGetter = (\n scopes: string | string[],\n options: GetTokenOptions,\n) => Promise<AccessToken>;\n\nexport interface TokenCyclerOptions {\n /**\n * The window of time before token expiration during which the token will be\n * considered unusable due to risk of the token expiring before sending the\n * request.\n *\n * This will only become meaningful if the refresh fails for over\n * (refreshWindow - forcedRefreshWindow) milliseconds.\n */\n forcedRefreshWindowInMs: number;\n /**\n * Interval in milliseconds to retry failed token refreshes.\n */\n retryIntervalInMs: number;\n /**\n * The window of time before token expiration during which\n * we will attempt to refresh the token.\n */\n refreshWindowInMs: number;\n}\n\n// Default options for the cycler if none are provided\nexport const DEFAULT_CYCLER_OPTIONS: TokenCyclerOptions = {\n forcedRefreshWindowInMs: 1000, // Force waiting for a refresh 1s before the token expires\n retryIntervalInMs: 3000, // Allow refresh attempts every 3s\n refreshWindowInMs: 1000 * 60 * 2, // Start refreshing 2m before expiry\n};\n\n/**\n * Converts an an unreliable access token getter (which may resolve with null)\n * into an AccessTokenGetter by retrying the unreliable getter in a regular\n * interval.\n *\n * @param getAccessToken - A function that produces a promise of an access token that may fail by returning null.\n * @param retryIntervalInMs - The time (in milliseconds) to wait between retry attempts.\n * @param refreshTimeout - The timestamp after which the refresh attempt will fail, throwing an exception.\n * @returns - A promise that, if it resolves, will resolve with an access token.\n */\nasync function beginRefresh(\n getAccessToken: () => Promise<AccessToken | null>,\n retryIntervalInMs: number,\n refreshTimeout: number,\n): Promise<AccessToken> {\n // This wrapper handles exceptions gracefully as long as we haven't exceeded\n // the timeout.\n async function tryGetAccessToken(): Promise<AccessToken | null> {\n if (Date.now() < refreshTimeout) {\n try {\n return await getAccessToken();\n } catch {\n return null;\n }\n } else {\n const finalToken = await getAccessToken();\n\n // Timeout is up, so throw if it's still null\n if (finalToken === null) {\n throw new Error(\"Failed to refresh access token.\");\n }\n\n return finalToken;\n }\n }\n\n let token: AccessToken | null = await tryGetAccessToken();\n\n while (token === null) {\n await delay(retryIntervalInMs);\n\n token = await tryGetAccessToken();\n }\n\n return token;\n}\n\n/**\n * Creates a token cycler from a credential, scopes, and optional settings.\n *\n * A token cycler represents a way to reliably retrieve a valid access token\n * from a TokenCredential. It will handle initializing the token, refreshing it\n * when it nears expiration, and synchronizes refresh attempts to avoid\n * concurrency hazards.\n *\n * @param credential - the underlying TokenCredential that provides the access\n * token\n * @param tokenCyclerOptions - optionally override default settings for the cycler\n *\n * @returns - a function that reliably produces a valid access token\n */\nexport function createTokenCycler(\n credential: TokenCredential,\n tokenCyclerOptions?: Partial<TokenCyclerOptions>,\n): AccessTokenGetter {\n let refreshWorker: Promise<AccessToken> | null = null;\n let token: AccessToken | null = null;\n let tenantId: string | undefined;\n\n const options = {\n ...DEFAULT_CYCLER_OPTIONS,\n ...tokenCyclerOptions,\n };\n\n /**\n * This little holder defines several predicates that we use to construct\n * the rules of refreshing the token.\n */\n const cycler = {\n /**\n * Produces true if a refresh job is currently in progress.\n */\n get isRefreshing(): boolean {\n return refreshWorker !== null;\n },\n /**\n * Produces true if the cycler SHOULD refresh (we are within the refresh\n * window and not already refreshing)\n */\n get shouldRefresh(): boolean {\n if (cycler.isRefreshing) {\n return false;\n }\n if (token?.refreshAfterTimestamp && token.refreshAfterTimestamp < Date.now()) {\n return true;\n }\n\n return (token?.expiresOnTimestamp ?? 0) - options.refreshWindowInMs < Date.now();\n },\n /**\n * Produces true if the cycler MUST refresh (null or nearly-expired\n * token).\n */\n get mustRefresh(): boolean {\n return (\n token === null || token.expiresOnTimestamp - options.forcedRefreshWindowInMs < Date.now()\n );\n },\n };\n\n /**\n * Starts a refresh job or returns the existing job if one is already\n * running.\n */\n function refresh(\n scopes: string | string[],\n getTokenOptions: GetTokenOptions,\n ): Promise<AccessToken> {\n if (!cycler.isRefreshing) {\n // We bind `scopes` here to avoid passing it around a lot\n const tryGetAccessToken = (): Promise<AccessToken | null> =>\n credential.getToken(scopes, getTokenOptions);\n\n // Take advantage of promise chaining to insert an assignment to `token`\n // before the refresh can be considered done.\n refreshWorker = beginRefresh(\n tryGetAccessToken,\n options.retryIntervalInMs,\n // If we don't have a token, then we should timeout immediately\n token?.expiresOnTimestamp ?? Date.now(),\n )\n .then((_token) => {\n refreshWorker = null;\n token = _token;\n tenantId = getTokenOptions.tenantId;\n return token;\n })\n .catch((reason) => {\n // We also should reset the refresher if we enter a failed state. All\n // existing awaiters will throw, but subsequent requests will start a\n // new retry chain.\n refreshWorker = null;\n token = null;\n tenantId = undefined;\n throw reason;\n });\n }\n\n return refreshWorker as Promise<AccessToken>;\n }\n\n return async (scopes: string | string[], tokenOptions: GetTokenOptions): Promise<AccessToken> => {\n //\n // Simple rules:\n // - If we MUST refresh, then return the refresh task, blocking\n // the pipeline until a token is available.\n // - If we SHOULD refresh, then run refresh but don't return it\n // (we can still use the cached token).\n // - Return the token, since it's fine if we didn't return in\n // step 1.\n //\n\n const hasClaimChallenge = Boolean(tokenOptions.claims);\n const tenantIdChanged = tenantId !== tokenOptions.tenantId;\n\n if (hasClaimChallenge) {\n // If we've received a claim, we know the existing token isn't valid\n // We want to clear it so that that refresh worker won't use the old expiration time as a timeout\n token = null;\n }\n\n // If the tenantId passed in token options is different to the one we have\n // Or if we are in claim challenge and the token was rejected and a new access token need to be issued, we need to\n // refresh the token with the new tenantId or token.\n const mustRefresh = tenantIdChanged || hasClaimChallenge || cycler.mustRefresh;\n\n if (mustRefresh) {\n return refresh(scopes, tokenOptions);\n }\n\n if (cycler.shouldRefresh) {\n refresh(scopes, tokenOptions);\n }\n\n return token as AccessToken;\n };\n}\n"]}
|