Skip to content

Commit 4f892d6

Browse files
authored
feat: Add optional cancellation token for oauth client
1 parent f9fb116 commit 4f892d6

File tree

4 files changed

+45
-31
lines changed

4 files changed

+45
-31
lines changed

Octokit.Reactive/Clients/IObservableOauthClient.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Threading;
23

34
namespace Octokit.Reactive
45
{
@@ -22,8 +23,9 @@ public interface IObservableOauthClient
2223
/// an access token using this method.
2324
/// </remarks>
2425
/// <param name="request"></param>
26+
/// <param name="cancellationToken"></param>
2527
/// <returns></returns>
26-
IObservable<OauthToken> CreateAccessToken(OauthTokenRequest request);
28+
IObservable<OauthToken> CreateAccessToken(OauthTokenRequest request, CancellationToken cancellationToken = default);
2729

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

3942
/// <summary>
40-
/// Makes a request to get an access token using the response from <see cref="InitiateDeviceFlow(OauthDeviceFlowRequest)"/>.
43+
/// Makes a request to get an access token using the response from <see cref="InitiateDeviceFlow(OauthDeviceFlowRequest, CancellationToken)"/>.
4144
/// </summary>
4245
/// <remarks>
4346
/// 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.
4447
/// </remarks>
4548
/// <param name="clientId">The client Id you received from GitHub when you registered the application.</param>
46-
/// <param name="deviceFlowResponse">The response you received from <see cref="InitiateDeviceFlow(OauthDeviceFlowRequest)"/></param>
49+
/// <param name="deviceFlowResponse">The response you received from <see cref="InitiateDeviceFlow(OauthDeviceFlowRequest, CancellationToken)"/></param>
50+
/// <param name="cancellationToken"></param>
4751
/// <returns></returns>
48-
IObservable<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, OauthDeviceFlowResponse deviceFlowResponse);
52+
IObservable<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, OauthDeviceFlowResponse deviceFlowResponse, CancellationToken cancellationToken = default);
4953

5054
/// <summary>
51-
/// Makes a request to get an access token using the refresh token returned in <see cref="CreateAccessToken(OauthTokenRequest)"/>.
55+
/// Makes a request to get an access token using the refresh token returned in <see cref="CreateAccessToken(OauthTokenRequest, CancellationToken)"/>.
5256
/// </summary>
5357
/// <param name="request">Token renewal request.</param>
58+
/// <param name="cancellationToken"></param>
5459
/// <returns><see cref="OauthToken"/> with the new token set.</returns>
55-
IObservable<OauthToken> CreateAccessTokenFromRenewalToken(OauthTokenRenewalRequest request);
60+
IObservable<OauthToken> CreateAccessTokenFromRenewalToken(OauthTokenRenewalRequest request, CancellationToken cancellationToken = default);
5661
}
5762
}

Octokit.Reactive/Clients/ObservableOauthClient.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Reactive.Threading.Tasks;
3+
using System.Threading;
34

45
namespace Octokit.Reactive
56
{
@@ -23,24 +24,24 @@ public Uri GetGitHubLoginUrl(OauthLoginRequest request)
2324
return _client.Oauth.GetGitHubLoginUrl(request);
2425
}
2526

26-
public IObservable<OauthToken> CreateAccessToken(OauthTokenRequest request)
27+
public IObservable<OauthToken> CreateAccessToken(OauthTokenRequest request, CancellationToken cancellationToken = default)
2728
{
28-
return _client.Oauth.CreateAccessToken(request).ToObservable();
29+
return _client.Oauth.CreateAccessToken(request, cancellationToken).ToObservable();
2930
}
3031

31-
public IObservable<OauthDeviceFlowResponse> InitiateDeviceFlow(OauthDeviceFlowRequest request)
32+
public IObservable<OauthDeviceFlowResponse> InitiateDeviceFlow(OauthDeviceFlowRequest request, CancellationToken cancellationToken = default)
3233
{
33-
return _client.Oauth.InitiateDeviceFlow(request).ToObservable();
34+
return _client.Oauth.InitiateDeviceFlow(request, cancellationToken).ToObservable();
3435
}
3536

36-
public IObservable<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, OauthDeviceFlowResponse deviceFlowResponse)
37+
public IObservable<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, OauthDeviceFlowResponse deviceFlowResponse, CancellationToken cancellationToken = default)
3738
{
38-
return _client.Oauth.CreateAccessTokenForDeviceFlow(clientId, deviceFlowResponse).ToObservable();
39+
return _client.Oauth.CreateAccessTokenForDeviceFlow(clientId, deviceFlowResponse, cancellationToken).ToObservable();
3940
}
4041

41-
public IObservable<OauthToken> CreateAccessTokenFromRenewalToken(OauthTokenRenewalRequest request)
42+
public IObservable<OauthToken> CreateAccessTokenFromRenewalToken(OauthTokenRenewalRequest request, CancellationToken cancellationToken = default)
4243
{
43-
return _client.Oauth.CreateAccessTokenFromRenewalToken(request)
44+
return _client.Oauth.CreateAccessTokenFromRenewalToken(request, cancellationToken)
4445
.ToObservable();
4546
}
4647
}

Octokit/Clients/IOAuthClient.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Threading;
23
using System.Threading.Tasks;
34

45
namespace Octokit
@@ -26,8 +27,9 @@ public interface IOauthClient
2627
/// an access token using this method.
2728
/// </remarks>
2829
/// <param name="request"></param>
30+
/// <param name="concellationToken"></param>
2931
/// <returns></returns>
30-
Task<OauthToken> CreateAccessToken(OauthTokenRequest request);
32+
Task<OauthToken> CreateAccessToken(OauthTokenRequest request, CancellationToken concellationToken = default);
3133

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

4346
/// <summary>
44-
/// Makes a request to get an access token using the response from <see cref="InitiateDeviceFlow(OauthDeviceFlowRequest)"/>.
47+
/// Makes a request to get an access token using the response from <see cref="InitiateDeviceFlow(OauthDeviceFlowRequest, CancellationToken)"/>.
4548
/// </summary>
4649
/// <remarks>
4750
/// 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.
4851
/// </remarks>
4952
/// <param name="clientId">The client Id you received from GitHub when you registered the application.</param>
50-
/// <param name="deviceFlowResponse">The response you received from <see cref="InitiateDeviceFlow(OauthDeviceFlowRequest)"/></param>
53+
/// <param name="deviceFlowResponse">The response you received from <see cref="InitiateDeviceFlow(OauthDeviceFlowRequest, CancellationToken)"/></param>
54+
/// <param name="concellationToken"></param>
5155
/// <returns></returns>
52-
Task<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, OauthDeviceFlowResponse deviceFlowResponse);
56+
Task<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, OauthDeviceFlowResponse deviceFlowResponse, CancellationToken concellationToken = default);
5357

5458
/// <summary>
55-
/// Makes a request to get an access token using the refresh token returned in <see cref="CreateAccessToken(OauthTokenRequest)"/>.
59+
/// Makes a request to get an access token using the refresh token returned in <see cref="CreateAccessToken(OauthTokenRequest, CancellationToken)"/>.
5660
/// </summary>
5761
/// <param name="request">Token renewal request.</param>
62+
/// <param name="concellationToken"></param>
5863
/// <returns><see cref="OauthToken"/> with the new token set.</returns>
59-
Task<OauthToken> CreateAccessTokenFromRenewalToken(OauthTokenRenewalRequest request);
64+
Task<OauthToken> CreateAccessTokenFromRenewalToken(OauthTokenRenewalRequest request, CancellationToken concellationToken = default);
6065
}
6166
}

Octokit/Clients/OAuthClient.cs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Globalization;
33
using System.Net.Http;
4+
using System.Threading;
45
using System.Threading.Tasks;
56

67
namespace Octokit
@@ -48,33 +49,33 @@ public Uri GetGitHubLoginUrl(OauthLoginRequest request)
4849
}
4950

5051
[ManualRoute("POST", "/login/oauth/access_token")]
51-
public async Task<OauthToken> CreateAccessToken(OauthTokenRequest request)
52+
public async Task<OauthToken> CreateAccessToken(OauthTokenRequest request, CancellationToken cancellationToken = default)
5253
{
5354
Ensure.ArgumentNotNull(request, nameof(request));
5455

5556
var endPoint = ApiUrls.OauthAccessToken();
5657

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

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

6364
[ManualRoute("POST", "/login/device/code")]
64-
public async Task<OauthDeviceFlowResponse> InitiateDeviceFlow(OauthDeviceFlowRequest request)
65+
public async Task<OauthDeviceFlowResponse> InitiateDeviceFlow(OauthDeviceFlowRequest request, CancellationToken cancellationToken = default)
6566
{
6667
Ensure.ArgumentNotNull(request, nameof(request));
6768

6869
var endPoint = ApiUrls.OauthDeviceCode();
6970

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

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

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

8687
while (true)
8788
{
89+
cancellationToken.ThrowIfCancellationRequested();
90+
8891
var request = new OauthTokenRequestForDeviceFlow(clientId, deviceFlowResponse.DeviceCode);
8992
var body = new FormUrlEncodedContent(request.ToParametersDictionary());
90-
var response = await connection.Post<OauthToken>(endPoint, body, "application/json", null, hostAddress).ConfigureAwait(false);
93+
var response = await connection.Post<OauthToken>(endPoint, body, "application/json", null, hostAddress, cancellationToken).ConfigureAwait(false);
9194

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

106-
await Task.Delay(TimeSpan.FromSeconds(pollingDelay));
109+
await Task.Delay(TimeSpan.FromSeconds(pollingDelay), cancellationToken);
107110
}
108111
else
109112
{
@@ -113,14 +116,14 @@ public async Task<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, Oa
113116
}
114117

115118
[ManualRoute("POST", "/login/oauth/access_token")]
116-
public async Task<OauthToken> CreateAccessTokenFromRenewalToken(OauthTokenRenewalRequest request)
119+
public async Task<OauthToken> CreateAccessTokenFromRenewalToken(OauthTokenRenewalRequest request, CancellationToken cancellationToken = default)
117120
{
118121
Ensure.ArgumentNotNull(request, nameof(request));
119122

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

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

0 commit comments

Comments
 (0)