Trait AuthStrategy
pub trait AuthStrategy: Send {
// Required method
fn get_token(
self,
) -> impl Future<Output = Result<ServiceToken, AuthError>> + Send;
}Expand description
A strategy for obtaining access tokens.
Implementations handle all details of authentication, token caching, and
refresh. Callers just call get_token whenever
they need a valid token.
The trait is designed to be implemented for &T, so that callers can use
shared references (e.g. &OAuthStrategy) without consuming the strategy.
§Token refresh
All strategies that cache tokens (AccessKeyStrategy, OAuthStrategy,
AutoStrategy) share the same internal refresh engine. Understanding the
refresh model helps predict how get_token
behaves under concurrent access.
§Expiry vs usability
A token has two time thresholds:
- Expired — the token is within 90 seconds of its
expires_attimestamp. This triggers a preemptive refresh attempt. - Usable — the token has not yet reached its
expires_attimestamp. A token can be “expired” (in the preemptive sense) but still “usable” (the server will still accept it).
§Concurrent refresh strategies
The gap between “expired” and “unusable” enables two refresh modes:
- Expiring but still usable — The first caller triggers a background refresh. Concurrent callers receive the current (still-valid) token immediately without blocking.
- Fully expired — The first caller blocks while refreshing. Concurrent callers wait until the refresh completes, then all receive the new token.
Only one refresh runs at a time, regardless of how many callers request a token concurrently.
§Flow diagram
flowchart TD
Start["get_token()"] --> Lock["Acquire lock"]
Lock --> Cached{Token cached?}
Cached -- No --> InitAuth["Authenticate
(lock held)"]
InitAuth -- OK --> ReturnNew["Return new token"]
InitAuth -- NotFound --> ErrNotFound["NotAuthenticated"]
InitAuth -- Err --> ErrAuth["Return error"]
Cached -- Yes --> CheckRefresh{Expired?}
CheckRefresh -- "No (fresh)" --> ReturnOk["Return cached token"]
CheckRefresh -- "Yes (needs refresh)" --> InProgress{Refresh in progress?}
InProgress -- Yes --> WaitOrReturn["Return token if usable,
else wait for refresh"]
WaitOrReturn -- OK --> ReturnOk
WaitOrReturn -- "refresh failed" --> ErrExpired["TokenExpired"]
InProgress -- No --> HasCred{Refresh credential?}
HasCred -- None --> CheckUsable["Return token if usable,
else TokenExpired"]
HasCred -- Yes --> Usable{Still usable?}
Usable -- "Yes (preemptive)" --> NonBlocking["Refresh in background
(lock released)"]
NonBlocking --> ReturnOld["Return current token"]
Usable -- "No (fully expired)" --> Blocking["Refresh
(lock held)"]
Blocking -- OK --> ReturnNew2["Return new token"]
Blocking -- Err --> ErrExpired["TokenExpired"]Required Methods§
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.