Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional cancellation token for oauth client #2988

Merged
merged 1 commit into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions Octokit.Reactive/Clients/IObservableOauthClient.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Threading;

namespace Octokit.Reactive
{
Expand All @@ -22,8 +23,9 @@ public interface IObservableOauthClient
/// an access token using this method.
/// </remarks>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
IObservable<OauthToken> CreateAccessToken(OauthTokenRequest request);
IObservable<OauthToken> CreateAccessToken(OauthTokenRequest request, CancellationToken cancellationToken = default);

/// <summary>
/// Makes a request to initiate the device flow authentication.
Expand All @@ -33,25 +35,28 @@ public interface IObservableOauthClient
/// This request also returns a device verification code that you must use to receive an access token to check the status of user authentication.
/// </remarks>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
IObservable<OauthDeviceFlowResponse> InitiateDeviceFlow(OauthDeviceFlowRequest request);
IObservable<OauthDeviceFlowResponse> InitiateDeviceFlow(OauthDeviceFlowRequest request, CancellationToken cancellationToken = default);

/// <summary>
/// Makes a request to get an access token using the response from <see cref="InitiateDeviceFlow(OauthDeviceFlowRequest)"/>.
/// Makes a request to get an access token using the response from <see cref="InitiateDeviceFlow(OauthDeviceFlowRequest, CancellationToken)"/>.
/// </summary>
/// <remarks>
/// Will poll the access token endpoint, until the device and user codes expire or the user has successfully authorized the app with a valid user code.
/// </remarks>
/// <param name="clientId">The client Id you received from GitHub when you registered the application.</param>
/// <param name="deviceFlowResponse">The response you received from <see cref="InitiateDeviceFlow(OauthDeviceFlowRequest)"/></param>
/// <param name="deviceFlowResponse">The response you received from <see cref="InitiateDeviceFlow(OauthDeviceFlowRequest, CancellationToken)"/></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
IObservable<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, OauthDeviceFlowResponse deviceFlowResponse);
IObservable<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, OauthDeviceFlowResponse deviceFlowResponse, CancellationToken cancellationToken = default);

/// <summary>
/// Makes a request to get an access token using the refresh token returned in <see cref="CreateAccessToken(OauthTokenRequest)"/>.
/// Makes a request to get an access token using the refresh token returned in <see cref="CreateAccessToken(OauthTokenRequest, CancellationToken)"/>.
/// </summary>
/// <param name="request">Token renewal request.</param>
/// <param name="cancellationToken"></param>
/// <returns><see cref="OauthToken"/> with the new token set.</returns>
IObservable<OauthToken> CreateAccessTokenFromRenewalToken(OauthTokenRenewalRequest request);
IObservable<OauthToken> CreateAccessTokenFromRenewalToken(OauthTokenRenewalRequest request, CancellationToken cancellationToken = default);
}
}
17 changes: 9 additions & 8 deletions Octokit.Reactive/Clients/ObservableOauthClient.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Reactive.Threading.Tasks;
using System.Threading;

namespace Octokit.Reactive
{
Expand All @@ -23,24 +24,24 @@ public Uri GetGitHubLoginUrl(OauthLoginRequest request)
return _client.Oauth.GetGitHubLoginUrl(request);
}

public IObservable<OauthToken> CreateAccessToken(OauthTokenRequest request)
public IObservable<OauthToken> CreateAccessToken(OauthTokenRequest request, CancellationToken cancellationToken = default)
{
return _client.Oauth.CreateAccessToken(request).ToObservable();
return _client.Oauth.CreateAccessToken(request, cancellationToken).ToObservable();
}

public IObservable<OauthDeviceFlowResponse> InitiateDeviceFlow(OauthDeviceFlowRequest request)
public IObservable<OauthDeviceFlowResponse> InitiateDeviceFlow(OauthDeviceFlowRequest request, CancellationToken cancellationToken = default)
{
return _client.Oauth.InitiateDeviceFlow(request).ToObservable();
return _client.Oauth.InitiateDeviceFlow(request, cancellationToken).ToObservable();
}

public IObservable<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, OauthDeviceFlowResponse deviceFlowResponse)
public IObservable<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, OauthDeviceFlowResponse deviceFlowResponse, CancellationToken cancellationToken = default)
{
return _client.Oauth.CreateAccessTokenForDeviceFlow(clientId, deviceFlowResponse).ToObservable();
return _client.Oauth.CreateAccessTokenForDeviceFlow(clientId, deviceFlowResponse, cancellationToken).ToObservable();
}

public IObservable<OauthToken> CreateAccessTokenFromRenewalToken(OauthTokenRenewalRequest request)
public IObservable<OauthToken> CreateAccessTokenFromRenewalToken(OauthTokenRenewalRequest request, CancellationToken cancellationToken = default)
{
return _client.Oauth.CreateAccessTokenFromRenewalToken(request)
return _client.Oauth.CreateAccessTokenFromRenewalToken(request, cancellationToken)
.ToObservable();
}
}
Expand Down
19 changes: 12 additions & 7 deletions Octokit/Clients/IOAuthClient.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Octokit
Expand Down Expand Up @@ -26,8 +27,9 @@ public interface IOauthClient
/// an access token using this method.
/// </remarks>
/// <param name="request"></param>
/// <param name="concellationToken"></param>
/// <returns></returns>
Task<OauthToken> CreateAccessToken(OauthTokenRequest request);
Task<OauthToken> CreateAccessToken(OauthTokenRequest request, CancellationToken concellationToken = default);

/// <summary>
/// Makes a request to initiate the device flow authentication.
Expand All @@ -37,25 +39,28 @@ public interface IOauthClient
/// This request also returns a device verification code that you must use to receive an access token to check the status of user authentication.
/// </remarks>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<OauthDeviceFlowResponse> InitiateDeviceFlow(OauthDeviceFlowRequest request);
Task<OauthDeviceFlowResponse> InitiateDeviceFlow(OauthDeviceFlowRequest request, CancellationToken cancellationToken = default);

/// <summary>
/// Makes a request to get an access token using the response from <see cref="InitiateDeviceFlow(OauthDeviceFlowRequest)"/>.
/// Makes a request to get an access token using the response from <see cref="InitiateDeviceFlow(OauthDeviceFlowRequest, CancellationToken)"/>.
/// </summary>
/// <remarks>
/// Will poll the access token endpoint, until the device and user codes expire or the user has successfully authorized the app with a valid user code.
/// </remarks>
/// <param name="clientId">The client Id you received from GitHub when you registered the application.</param>
/// <param name="deviceFlowResponse">The response you received from <see cref="InitiateDeviceFlow(OauthDeviceFlowRequest)"/></param>
/// <param name="deviceFlowResponse">The response you received from <see cref="InitiateDeviceFlow(OauthDeviceFlowRequest, CancellationToken)"/></param>
/// <param name="concellationToken"></param>
/// <returns></returns>
Task<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, OauthDeviceFlowResponse deviceFlowResponse);
Task<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, OauthDeviceFlowResponse deviceFlowResponse, CancellationToken concellationToken = default);

/// <summary>
/// Makes a request to get an access token using the refresh token returned in <see cref="CreateAccessToken(OauthTokenRequest)"/>.
/// Makes a request to get an access token using the refresh token returned in <see cref="CreateAccessToken(OauthTokenRequest, CancellationToken)"/>.
/// </summary>
/// <param name="request">Token renewal request.</param>
/// <param name="concellationToken"></param>
/// <returns><see cref="OauthToken"/> with the new token set.</returns>
Task<OauthToken> CreateAccessTokenFromRenewalToken(OauthTokenRenewalRequest request);
Task<OauthToken> CreateAccessTokenFromRenewalToken(OauthTokenRenewalRequest request, CancellationToken concellationToken = default);
}
}
21 changes: 12 additions & 9 deletions Octokit/Clients/OAuthClient.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Globalization;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace Octokit
Expand Down Expand Up @@ -48,33 +49,33 @@ public Uri GetGitHubLoginUrl(OauthLoginRequest request)
}

[ManualRoute("POST", "/login/oauth/access_token")]
public async Task<OauthToken> CreateAccessToken(OauthTokenRequest request)
public async Task<OauthToken> CreateAccessToken(OauthTokenRequest request, CancellationToken cancellationToken = default)
{
Ensure.ArgumentNotNull(request, nameof(request));

var endPoint = ApiUrls.OauthAccessToken();

var body = new FormUrlEncodedContent(request.ToParametersDictionary());

var response = await connection.Post<OauthToken>(endPoint, body, "application/json", null, hostAddress).ConfigureAwait(false);
var response = await connection.Post<OauthToken>(endPoint, body, "application/json", null, hostAddress, cancellationToken).ConfigureAwait(false);
return response.Body;
}

[ManualRoute("POST", "/login/device/code")]
public async Task<OauthDeviceFlowResponse> InitiateDeviceFlow(OauthDeviceFlowRequest request)
public async Task<OauthDeviceFlowResponse> InitiateDeviceFlow(OauthDeviceFlowRequest request, CancellationToken cancellationToken = default)
{
Ensure.ArgumentNotNull(request, nameof(request));

var endPoint = ApiUrls.OauthDeviceCode();

var body = new FormUrlEncodedContent(request.ToParametersDictionary());

var response = await connection.Post<OauthDeviceFlowResponse>(endPoint, body, "application/json", null, hostAddress).ConfigureAwait(false);
var response = await connection.Post<OauthDeviceFlowResponse>(endPoint, body, "application/json", null, hostAddress, cancellationToken).ConfigureAwait(false);
return response.Body;
}

[ManualRoute("POST", "/login/oauth/access_token")]
public async Task<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, OauthDeviceFlowResponse deviceFlowResponse)
public async Task<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, OauthDeviceFlowResponse deviceFlowResponse, CancellationToken cancellationToken = default)
{
Ensure.ArgumentNotNullOrEmptyString(clientId, nameof(clientId));
Ensure.ArgumentNotNull(deviceFlowResponse, nameof(deviceFlowResponse));
Expand All @@ -85,9 +86,11 @@ public async Task<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, Oa

while (true)
{
cancellationToken.ThrowIfCancellationRequested();

var request = new OauthTokenRequestForDeviceFlow(clientId, deviceFlowResponse.DeviceCode);
var body = new FormUrlEncodedContent(request.ToParametersDictionary());
var response = await connection.Post<OauthToken>(endPoint, body, "application/json", null, hostAddress).ConfigureAwait(false);
var response = await connection.Post<OauthToken>(endPoint, body, "application/json", null, hostAddress, cancellationToken).ConfigureAwait(false);

if (response.Body.Error != null)
{
Expand All @@ -103,7 +106,7 @@ public async Task<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, Oa
throw new ApiException(string.Format(CultureInfo.InvariantCulture, "{0}: {1}\n{2}", response.Body.Error, response.Body.ErrorDescription, response.Body.ErrorUri), null);
}

await Task.Delay(TimeSpan.FromSeconds(pollingDelay));
await Task.Delay(TimeSpan.FromSeconds(pollingDelay), cancellationToken);
}
else
{
Expand All @@ -113,14 +116,14 @@ public async Task<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, Oa
}

[ManualRoute("POST", "/login/oauth/access_token")]
public async Task<OauthToken> CreateAccessTokenFromRenewalToken(OauthTokenRenewalRequest request)
public async Task<OauthToken> CreateAccessTokenFromRenewalToken(OauthTokenRenewalRequest request, CancellationToken cancellationToken = default)
{
Ensure.ArgumentNotNull(request, nameof(request));

var endPoint = ApiUrls.OauthAccessToken();
var body = new FormUrlEncodedContent(request.ToParametersDictionary());

var response = await connection.Post<OauthToken>(endPoint, body, "application/json", null, hostAddress).ConfigureAwait(false);
var response = await connection.Post<OauthToken>(endPoint, body, "application/json", null, hostAddress, cancellationToken).ConfigureAwait(false);
return response.Body;
}
}
Expand Down
Loading