Skip to content

Add OAuth2 token lifecycle authenticators (client credentials, refresh token, custom provider) #2361

@alexeyzimarev

Description

@alexeyzimarev

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions