mirror of
https://github.com/zoriya/octokit.net.git
synced 2025-12-06 07:16:09 +00:00
* Support refreshtokens in OAuth flow Fixes #2731 * Added summary to OauthToken.cs constructors * Mark deprecation of non-refreshToken constructor for OauthToken * Remove unnecessary comment --------- Co-authored-by: Keegan Campbell <me@kfcampbell.com>
128 lines
5.1 KiB
C#
128 lines
5.1 KiB
C#
using System;
|
|
using System.Globalization;
|
|
using System.Net.Http;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Octokit
|
|
{
|
|
/// <summary>
|
|
/// Provides methods used in the OAuth web flow.
|
|
/// </summary>
|
|
/// <inheritdoc />
|
|
public class OauthClient : IOauthClient
|
|
{
|
|
readonly IConnection connection;
|
|
readonly Uri hostAddress;
|
|
|
|
/// <summary>
|
|
/// Create an instance of the OauthClient
|
|
/// </summary>
|
|
/// <param name="connection">The underlying connection to use</param>
|
|
public OauthClient(IConnection connection)
|
|
{
|
|
Ensure.ArgumentNotNull(connection, nameof(connection));
|
|
|
|
this.connection = connection;
|
|
var baseAddress = connection.BaseAddress ?? GitHubClient.GitHubDotComUrl;
|
|
|
|
// The Oauth login stuff uses the main website and not the API URLs
|
|
// For https://api.github.com we use https://github.com
|
|
// For any other address (presumably a GitHub Enterprise address) we need to strip any relative Uri such as /api/v3
|
|
hostAddress = baseAddress.Host.Equals("api.github.com")
|
|
? new Uri("https://github.com")
|
|
: baseAddress.StripRelativeUri();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the URL used in the first step of the web flow. The Web application should redirect to this URL.
|
|
/// </summary>
|
|
/// <param name="request">Parameters to the Oauth web flow login url</param>
|
|
/// <returns></returns>
|
|
[DotNetSpecificRoute]
|
|
public Uri GetGitHubLoginUrl(OauthLoginRequest request)
|
|
{
|
|
Ensure.ArgumentNotNull(request, nameof(request));
|
|
|
|
return new Uri(hostAddress, ApiUrls.OauthAuthorize())
|
|
.ApplyParameters(request.ToParametersDictionary());
|
|
}
|
|
|
|
[ManualRoute("POST", "/login/oauth/access_token")]
|
|
public async Task<OauthToken> CreateAccessToken(OauthTokenRequest request)
|
|
{
|
|
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);
|
|
return response.Body;
|
|
}
|
|
|
|
[ManualRoute("POST", "/login/device/code")]
|
|
public async Task<OauthDeviceFlowResponse> InitiateDeviceFlow(OauthDeviceFlowRequest request)
|
|
{
|
|
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);
|
|
return response.Body;
|
|
}
|
|
|
|
[ManualRoute("POST", "/login/oauth/access_token")]
|
|
public async Task<OauthToken> CreateAccessTokenForDeviceFlow(string clientId, OauthDeviceFlowResponse deviceFlowResponse)
|
|
{
|
|
Ensure.ArgumentNotNullOrEmptyString(clientId, nameof(clientId));
|
|
Ensure.ArgumentNotNull(deviceFlowResponse, nameof(deviceFlowResponse));
|
|
|
|
var endPoint = ApiUrls.OauthAccessToken();
|
|
|
|
int pollingDelay = deviceFlowResponse.Interval;
|
|
|
|
while (true)
|
|
{
|
|
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);
|
|
|
|
if (response.Body.Error != null)
|
|
{
|
|
switch (response.Body.Error)
|
|
{
|
|
case "authorization_pending":
|
|
break;
|
|
case "slow_down":
|
|
pollingDelay += 5;
|
|
break;
|
|
case "expired_token":
|
|
default:
|
|
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));
|
|
}
|
|
else
|
|
{
|
|
return response.Body;
|
|
}
|
|
}
|
|
}
|
|
|
|
[ManualRoute("POST", "/login/oauth/access_token")]
|
|
public async Task<OauthToken> CreateAccessTokenFromRenewalToken(OauthTokenRenewalRequest request)
|
|
{
|
|
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);
|
|
return response.Body;
|
|
}
|
|
}
|
|
}
|