Skip to content

Commit b9d313e

Browse files
authored
handle tokens that expire immediately in AutoRefreshingTokenCredential (#1176)
This removes the looping in `AutoRefreshingTokenCredential` as at least one of the providers, in particular `AzureCliCredential` returns tokens that expire immediately, indicating the token should always be refreshed before reuse. This addresses #1143
1 parent 6cc519e commit b9d313e

1 file changed

Lines changed: 26 additions & 19 deletions

File tree

sdk/identity/src/token_credentials/auto_refreshing_credentials.rs

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,31 +38,38 @@ impl AutoRefreshingTokenCredential {
3838
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
3939
impl TokenCredential for AutoRefreshingTokenCredential {
4040
async fn get_token(&self, resource: &str) -> azure_core::Result<TokenResponse> {
41+
// if the current cached token is good, return that.
4142
if let Some(Ok(token)) = self.current_token.read().await.as_ref() {
4243
if !is_expired(token) {
4344
return Ok(token.clone());
4445
}
4546
}
46-
loop {
47-
let mut guard = self.current_token.write().await;
48-
match guard.as_ref() {
49-
None => {
50-
let res = self.credential.get_token(resource).await;
51-
*guard = Some(res);
52-
}
53-
Some(Err(err)) => {
54-
return Err(Error::with_message(ErrorKind::Credential, || {
55-
err.to_string()
56-
}));
57-
}
58-
Some(Ok(token)) => {
59-
if is_expired(token) {
60-
*guard = None;
61-
} else {
62-
return Ok(token.clone());
63-
};
64-
}
47+
48+
let mut guard = self.current_token.write().await;
49+
50+
// check again in case another thread refreshed the token while we were
51+
// waiting on the write lock
52+
if let Some(Ok(token)) = guard.as_ref() {
53+
if !is_expired(token) {
54+
return Ok(token.clone());
6555
}
6656
}
57+
58+
let res = self.credential.get_token(resource).await;
59+
60+
// NOTE: we do not check to see if the token is expired here, as at
61+
// least one credential, `AzureCliCredential`, specifies the token is
62+
// immediately expired after it is returned, which indicates the token
63+
// should always be refreshed upon use.
64+
let result = match &res {
65+
Ok(token) => Ok(token.clone()),
66+
Err(err) => Err(Error::with_message(ErrorKind::Credential, || {
67+
err.to_string()
68+
})),
69+
};
70+
71+
*guard = Some(res);
72+
73+
result
6774
}
6875
}

0 commit comments

Comments
 (0)