Problem
RestSharp's existing OAuth2 authenticators (OAuth2AuthorizationRequestHeaderAuthenticator, OAuth2UriQueryParameterAuthenticator) are static token stampers — they take a pre-obtained token and add it to requests. They don't handle token acquisition, caching, expiry, or refresh.
Users who need automatic token lifecycle management hit a circular dependency: an authenticator that calls a token endpoint needs an HttpClient, but it lives inside the RestClient it's attached to. This was reported in #2101 as "replace the authenticator after creating the client," but the actual need is self-managing authenticators that handle the token lifecycle internally.
Solution
Three new authenticators that manage the full OAuth2 token lifecycle using their own internal HttpClient for token endpoint calls:
OAuth2ClientCredentialsAuthenticator
Machine-to-machine flow. POSTs grant_type=client_credentials to the token endpoint. Caches the token and refreshes automatically when expired. Thread-safe via SemaphoreSlim with double-check pattern.
OAuth2RefreshTokenAuthenticator
User token flow. Takes initial access + refresh tokens. When the access token expires, POSTs grant_type=refresh_token. Handles refresh token rotation. Fires a callback when tokens change so callers can persist them.
OAuth2TokenAuthenticator
Generic delegate-based authenticator. Takes Func<CancellationToken, Task<OAuth2Token>> for non-standard flows. Caches the result and re-invokes the delegate on expiry.
Shared types
OAuth2TokenResponse — RFC 6749 Section 5.1 token response model
OAuth2TokenRequest — Configuration for token endpoint calls (URL, client ID/secret, scope, expiry buffer, callback)
OAuth2Token — Simple record for the delegate-based authenticator
Key design decisions
- Each authenticator owns its own
HttpClient for token endpoint calls (avoids circular dependency with RestClient)
- User can provide their own
HttpClient via OAuth2TokenRequest.HttpClient (e.g., for proxies or mTLS)
Action<OAuth2TokenResponse> callback for token persistence
- No changes to existing APIs or behavior
Supersedes #2101.
Problem
RestSharp's existing OAuth2 authenticators (
OAuth2AuthorizationRequestHeaderAuthenticator,OAuth2UriQueryParameterAuthenticator) are static token stampers — they take a pre-obtained token and add it to requests. They don't handle token acquisition, caching, expiry, or refresh.Users who need automatic token lifecycle management hit a circular dependency: an authenticator that calls a token endpoint needs an
HttpClient, but it lives inside theRestClientit's attached to. This was reported in #2101 as "replace the authenticator after creating the client," but the actual need is self-managing authenticators that handle the token lifecycle internally.Solution
Three new authenticators that manage the full OAuth2 token lifecycle using their own internal
HttpClientfor token endpoint calls:OAuth2ClientCredentialsAuthenticatorMachine-to-machine flow. POSTs
grant_type=client_credentialsto the token endpoint. Caches the token and refreshes automatically when expired. Thread-safe viaSemaphoreSlimwith double-check pattern.OAuth2RefreshTokenAuthenticatorUser token flow. Takes initial access + refresh tokens. When the access token expires, POSTs
grant_type=refresh_token. Handles refresh token rotation. Fires a callback when tokens change so callers can persist them.OAuth2TokenAuthenticatorGeneric delegate-based authenticator. Takes
Func<CancellationToken, Task<OAuth2Token>>for non-standard flows. Caches the result and re-invokes the delegate on expiry.Shared types
OAuth2TokenResponse— RFC 6749 Section 5.1 token response modelOAuth2TokenRequest— Configuration for token endpoint calls (URL, client ID/secret, scope, expiry buffer, callback)OAuth2Token— Simple record for the delegate-based authenticatorKey design decisions
HttpClientfor token endpoint calls (avoids circular dependency withRestClient)HttpClientviaOAuth2TokenRequest.HttpClient(e.g., for proxies or mTLS)Action<OAuth2TokenResponse>callback for token persistenceSupersedes #2101.