Uh oh!
There was an error while loading. Please reload this page.
Add OAuth2 token lifecycle authenticators (#2361) - #2362
Conversation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Review Summary by QodoAdd OAuth2 token lifecycle authenticators with automatic acquisition and refresh
WalkthroughsDescription• Add three new OAuth2 authenticators for automatic token lifecycle management - OAuth2ClientCredentialsAuthenticator for machine-to-machine flows - OAuth2RefreshTokenAuthenticator for user token flows with refresh rotation - OAuth2TokenAuthenticator for custom/delegate-based token providers • Add shared OAuth2 data models following RFC 6749 Section 5.1 - OAuth2TokenResponse for token endpoint responses - OAuth2TokenRequest for token endpoint configuration - OAuth2Token for delegate-based authenticator return type • Implement thread-safe token caching and automatic refresh with SemaphoreSlim • Support custom HttpClient injection and token refresh callbacks for persistence Diagramflowchart LR
A["RestRequest"] -->|Authenticate| B["OAuth2 Authenticator"]
B -->|Token expired?| C["Acquire SemaphoreSlim"]
C -->|POST to token endpoint| D["Own HttpClient"]
D -->|Parse response| E["OAuth2TokenResponse"]
E -->|Cache token| F["Add Bearer header"]
F -->|Return| A
E -->|Fire callback| G["OnTokenRefreshed"]
File Changes1. src/RestSharp/Authenticators/OAuth2/OAuth2TokenResponse.cs
|
Code Review by Qodo
1. IAuthenticator signature changed |
Deploying restsharp with |
| Latest commit: | 2674757 |
| Status: | ✅ Deploy successful! |
| Preview URL: | https://90627df5.restsharp.pages.dev |
| Branch Preview URL: | https://feature-oauth2-token-lifecyc.restsharp.pages.dev |
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
OAuth2ClientCredentialsAuthenticator and OAuth2RefreshTokenAuthenticator shared ~60 lines of identical code for HttpClient management, locking, token parsing, error handling, and disposal. Extract into OAuth2EndpointAuthenticatorBase. Subclasses now only provide grant-specific parameters and post-response hooks. Fixes SonarCloud duplication gate (4.5% > 3% threshold). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Test Results 42 files 42 suites 19m 18s ⏱️ Results for commit 2674757. ♻️ This comment has been updated with latest results. |
…e on refresh - Add optional CancellationToken to IAuthenticator.Authenticate and propagate it through all authenticators to SemaphoreSlim.WaitAsync, HttpClient.PostAsync, and the user delegate in OAuth2TokenAuthenticator - Make OAuth2TokenResponse.ExpiresIn nullable (int?) so missing expires_in from the server is treated as non-expiring instead of causing a refresh storm - Send scope parameter in OAuth2RefreshTokenAuthenticator when configured Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
alexeyzimarev
commented
Mar 1, 2026
/review |
Persistent review updated to latest commit 2674757 |
| public interface IAuthenticator { | ||
| ValueTask Authenticate(IRestClient client, RestRequest request); | ||
| ValueTask Authenticate(IRestClient client, RestRequest request, CancellationToken cancellationToken = default); |
There was a problem hiding this comment.
1. iauthenticator signature changed 📎 Requirement gap✓ Correctness
The PR changes the public IAuthenticator.Authenticate method signature by adding a CancellationToken parameter, which is a breaking API change for any third-party IAuthenticator implementations. This violates the requirement to keep existing authenticator APIs/behavior unchanged when adding the new OAuth2 lifecycle authenticators.
Agent Prompt
## Issue description
`IAuthenticator.Authenticate` was changed to include an optional `CancellationToken`, which is a breaking public API change for any external implementers of `IAuthenticator`.
## Issue Context
The compliance checklist requires adding new OAuth2 lifecycle authenticators without breaking existing authenticator APIs/behavior. Changing the `IAuthenticator` method signature violates that constraint.
## Fix Focus Areas
- src/RestSharp/Authenticators/IAuthenticator.cs[17-19]
- src/RestSharp/Authenticators/AuthenticatorBase.cs[17-23]
- src/RestSharp/RestClient.Async.cs[108-112]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Summary
OAuth2ClientCredentialsAuthenticatorfor machine-to-machine flows with automatic token acquisition and refreshOAuth2RefreshTokenAuthenticatorfor user token flows with refresh token rotation supportOAuth2TokenAuthenticatorfor custom/non-standard flows via a delegate-based token providerOAuth2TokenResponse(RFC 6749),OAuth2TokenRequest,OAuth2TokenEach authenticator manages the full token lifecycle internally using its own
HttpClientfor token endpoint calls, eliminating the circular dependency described in #2101.Closes#2361
Design
HttpClientfor token endpoint calls (user can provide their own viaOAuth2TokenRequest.HttpClient)SemaphoreSlimwith double-check patternAction<OAuth2TokenResponse>callback for persisting refreshed tokensTest plan
🤖 Generated with Claude Code