[core-http] Rewrite bearerTokenAuthenticationPolicy#14223
Conversation
adede61 to
443f7b3
Compare
sadasant
left a comment
There was a problem hiding this comment.
Beautifully done! Thank you 👏
|
Check enforcer is running into some trouble this morning with events making it back from AZDO, but we're green on the merge of 75f9a1b: |
jeremymeng
left a comment
There was a problem hiding this comment.
Looks good to me. Would love to have @xirzec take a look too.
sdk/core/core-http/src/policies/bearerTokenAuthenticationPolicy.ts
Outdated
Show resolved
Hide resolved
xirzec
left a comment
There was a problem hiding this comment.
This is clever!
Can we mark AccessTokenRefresher and AccessTokenCache as deprecated as part of this PR?
The only other real concern I have is the case where getToken fails forever and we stubbornly never raise an error the developer can handle. Feels like there should be some limit.
sdk/core/core-http/src/policies/bearerTokenAuthenticationPolicy.ts
Outdated
Show resolved
Hide resolved
| scopes, | ||
| timeBetweenRefreshAttemptsInMs | ||
| ); | ||
| async function beginRefresh( |
There was a problem hiding this comment.
so this never gives up? Is there any case it could get stuck forever? What happens if I pass in a token credential with a bad endpoint or something?
There was a problem hiding this comment.
I can't think of any reason a TokenCredential would actually return null. It bothers me that the API is written in such a way that resolving with null is possible, but I think for compatibility reasons we are stuck with it. What I guess we should be doing here instead of checking for null is catching rejections.
We could just use a timer? If the refresh doesn't complete within five seconds after expiration (or within five seconds period if there is no token), we can just reject the refresher. Any requests queued up waiting for that refresh job will reject as well.
There was a problem hiding this comment.
I added the logic proposed by @sadasant below. If the existing token has already timed out, we retry one more time and then surface an exception to all awaiters if it failed again.
sdk/core/core-http/src/policies/bearerTokenAuthenticationPolicy.ts
Outdated
Show resolved
Hide resolved
|
@willmtemple @jeremymeng are we missing something here? just to make sure we're not missing anything. |
|
@sadasant I need to get back to this. I'll update this later today. I am wondering whether/what to do about the refreshing forever issue. Timeout seems pretty simple and low risk, and I'm wondering whether I should catch exceptions as well. |
|
@witemple-msft right when the token expires there should be at most one more refresh, and no more refreshes. After that we should assume we weren't able to refresh the token and let the network request throw naturally with the expired token. |
|
Hello @witemple-msft! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|

This is a total reimplementation of
bearerTokenAuthenticationPolicy. I'm proposing this because the existing implementation has some issues and relies on a class hierarchy that is unfortunately exposed through the core-http public API surface (and is therefore difficult to improve upon).In this implementation, the architecture looks like this:
bearerTokenAuthenticationPolicycreates a request policy factory that uses a "token cycler" and aSimpleBearerAuthorizationPolicyto manage applying bearer authorization to requests. The policy has no smarts other than asking the cycler for a token, applying it, and then applying the rest of the request policy chain.AccessTokenreliably. It is constructed from a TokenCredential and scopes.beginRefreshcreates a refresh job that takes a function producingAccessToken | nulland a refresh interval (in milliseconds, default of three seconds), and continually tries to retrieve an AccessToken until it is successful, waiting for the specified interval between attempts.This doesn't change (add or remove) any API surface.
I've also merged the tests that @sadasant helpfully provided and repaired them to work with the new default values.