mirror of
https://github.com/OpenAPITools/openapi-generator.git
synced 2025-05-12 12:40:53 +00:00
Merge branch 'AddRefreshToCsharpTemplate' of https://github.com/BryanAldrich/openapi-generator into BryanAldrich-AddRefreshToCsharpTemplate3
This commit is contained in:
commit
48ef1e6cf1
@ -11,8 +11,25 @@ namespace {{packageName}}.Client.Auth
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// An authenticator for OAuth2 authentication flows
|
/// An authenticator for OAuth2 authentication flows
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OAuthAuthenticator : AuthenticatorBase
|
public class OAuthAuthenticator : IAuthenticator
|
||||||
{
|
{
|
||||||
|
private TokenResponse{{nrt?}} _token;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the current authentication token. Can return null if there is no authentication token, or it has expired.
|
||||||
|
/// </summary>
|
||||||
|
public string{{nrt?}} Token
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_token == null) return null;
|
||||||
|
if (_token.ExpiresIn == null) return _token.AccessToken;
|
||||||
|
if (_token.ExpiresAt < DateTime.Now) return null;
|
||||||
|
|
||||||
|
return _token.AccessToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
readonly string _tokenUrl;
|
readonly string _tokenUrl;
|
||||||
readonly string _clientId;
|
readonly string _clientId;
|
||||||
readonly string _clientSecret;
|
readonly string _clientSecret;
|
||||||
@ -31,7 +48,7 @@ namespace {{packageName}}.Client.Auth
|
|||||||
string{{nrt?}} scope,
|
string{{nrt?}} scope,
|
||||||
OAuthFlow? flow,
|
OAuthFlow? flow,
|
||||||
JsonSerializerSettings serializerSettings,
|
JsonSerializerSettings serializerSettings,
|
||||||
IReadableConfiguration configuration) : base("")
|
IReadableConfiguration configuration)
|
||||||
{
|
{
|
||||||
_tokenUrl = tokenUrl;
|
_tokenUrl = tokenUrl;
|
||||||
_clientId = clientId;
|
_clientId = clientId;
|
||||||
@ -62,9 +79,8 @@ namespace {{packageName}}.Client.Auth
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an authentication parameter from an access token.
|
/// Creates an authentication parameter from an access token.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="accessToken">Access token to create a parameter from.</param>
|
|
||||||
/// <returns>An authentication parameter.</returns>
|
/// <returns>An authentication parameter.</returns>
|
||||||
protected override async ValueTask<Parameter> GetAuthenticationParameter(string accessToken)
|
protected async ValueTask<Parameter> GetAuthenticationParameter()
|
||||||
{
|
{
|
||||||
var token = string.IsNullOrEmpty(Token) ? await GetToken().ConfigureAwait(false) : Token;
|
var token = string.IsNullOrEmpty(Token) ? await GetToken().ConfigureAwait(false) : Token;
|
||||||
return new HeaderParameter(KnownHeaders.Authorization, token);
|
return new HeaderParameter(KnownHeaders.Authorization, token);
|
||||||
@ -76,31 +92,45 @@ namespace {{packageName}}.Client.Auth
|
|||||||
/// <returns>An authentication token.</returns>
|
/// <returns>An authentication token.</returns>
|
||||||
async Task<string> GetToken()
|
async Task<string> GetToken()
|
||||||
{
|
{
|
||||||
var client = new RestClient(_tokenUrl,
|
var client = new RestClient(_tokenUrl, configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));
|
||||||
configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));
|
|
||||||
|
|
||||||
var request = new RestRequest()
|
|
||||||
.AddParameter("grant_type", _grantType)
|
|
||||||
.AddParameter("client_id", _clientId)
|
|
||||||
.AddParameter("client_secret", _clientSecret);
|
|
||||||
|
|
||||||
|
var request = new RestRequest();
|
||||||
|
if (!string.IsNullOrWhiteSpace(_token?.RefreshToken))
|
||||||
|
{
|
||||||
|
request.AddParameter("grant_type", "refresh_token")
|
||||||
|
.AddParameter("refresh_token", _token.RefreshToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
request
|
||||||
|
.AddParameter("grant_type", _grantType)
|
||||||
|
.AddParameter("client_id", _clientId)
|
||||||
|
.AddParameter("client_secret", _clientSecret);
|
||||||
|
}
|
||||||
if (!string.IsNullOrEmpty(_scope))
|
if (!string.IsNullOrEmpty(_scope))
|
||||||
{
|
{
|
||||||
request.AddParameter("scope", _scope);
|
request.AddParameter("scope", _scope);
|
||||||
}
|
}
|
||||||
|
_token = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
|
||||||
var response = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// RFC6749 - token_type is case insensitive.
|
// RFC6749 - token_type is case insensitive.
|
||||||
// RFC6750 - In Authorization header Bearer should be capitalized.
|
// RFC6750 - In Authorization header Bearer should be capitalized.
|
||||||
// Fix the capitalization irrespective of token_type casing.
|
// Fix the capitalization irrespective of token_type casing.
|
||||||
switch (response.TokenType?.ToLower())
|
switch (_token?.TokenType?.ToLower())
|
||||||
{
|
{
|
||||||
case "bearer":
|
case "bearer":
|
||||||
return $"Bearer {response.AccessToken}";
|
return $"Bearer {_token.AccessToken}";
|
||||||
default:
|
default:
|
||||||
return $"{response.TokenType} {response.AccessToken}";
|
return $"{_token?.TokenType} {_token?.AccessToken}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the authentication token (creating a new one if necessary) and adds it to the current request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client"></param>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async ValueTask Authenticate(IRestClient client, RestRequest request)
|
||||||
|
=> request.AddOrUpdateParameter(await GetAuthenticationParameter().ConfigureAwait(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{{>partial_header}}
|
{{>partial_header}}
|
||||||
|
|
||||||
|
using System;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace {{packageName}}.Client.Auth
|
namespace {{packageName}}.Client.Auth
|
||||||
@ -10,5 +11,14 @@ namespace {{packageName}}.Client.Auth
|
|||||||
public string TokenType { get; set; }
|
public string TokenType { get; set; }
|
||||||
[JsonProperty("access_token")]
|
[JsonProperty("access_token")]
|
||||||
public string AccessToken { get; set; }
|
public string AccessToken { get; set; }
|
||||||
|
[JsonProperty("expires_in")]
|
||||||
|
public int? ExpiresIn { get; set; }
|
||||||
|
[JsonProperty("created")]
|
||||||
|
public DateTime? Created { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("refresh_token")]
|
||||||
|
public string{{nrt?}} RefreshToken { get; set; }
|
||||||
|
|
||||||
|
public DateTime? ExpiresAt => ExpiresIn == null ? null : Created?.AddSeconds(ExpiresIn.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,8 +19,25 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// An authenticator for OAuth2 authentication flows
|
/// An authenticator for OAuth2 authentication flows
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OAuthAuthenticator : AuthenticatorBase
|
public class OAuthAuthenticator : IAuthenticator
|
||||||
{
|
{
|
||||||
|
private TokenResponse _token;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the current authentication token. Can return null if there is no authentication token, or it has expired.
|
||||||
|
/// </summary>
|
||||||
|
public string Token
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_token == null) return null;
|
||||||
|
if (_token.ExpiresIn == null) return _token.AccessToken;
|
||||||
|
if (_token.ExpiresAt < DateTime.Now) return null;
|
||||||
|
|
||||||
|
return _token.AccessToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
readonly string _tokenUrl;
|
readonly string _tokenUrl;
|
||||||
readonly string _clientId;
|
readonly string _clientId;
|
||||||
readonly string _clientSecret;
|
readonly string _clientSecret;
|
||||||
@ -39,7 +56,7 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
string scope,
|
string scope,
|
||||||
OAuthFlow? flow,
|
OAuthFlow? flow,
|
||||||
JsonSerializerSettings serializerSettings,
|
JsonSerializerSettings serializerSettings,
|
||||||
IReadableConfiguration configuration) : base("")
|
IReadableConfiguration configuration)
|
||||||
{
|
{
|
||||||
_tokenUrl = tokenUrl;
|
_tokenUrl = tokenUrl;
|
||||||
_clientId = clientId;
|
_clientId = clientId;
|
||||||
@ -70,9 +87,8 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an authentication parameter from an access token.
|
/// Creates an authentication parameter from an access token.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="accessToken">Access token to create a parameter from.</param>
|
|
||||||
/// <returns>An authentication parameter.</returns>
|
/// <returns>An authentication parameter.</returns>
|
||||||
protected override async ValueTask<Parameter> GetAuthenticationParameter(string accessToken)
|
protected async ValueTask<Parameter> GetAuthenticationParameter()
|
||||||
{
|
{
|
||||||
var token = string.IsNullOrEmpty(Token) ? await GetToken().ConfigureAwait(false) : Token;
|
var token = string.IsNullOrEmpty(Token) ? await GetToken().ConfigureAwait(false) : Token;
|
||||||
return new HeaderParameter(KnownHeaders.Authorization, token);
|
return new HeaderParameter(KnownHeaders.Authorization, token);
|
||||||
@ -84,31 +100,45 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <returns>An authentication token.</returns>
|
/// <returns>An authentication token.</returns>
|
||||||
async Task<string> GetToken()
|
async Task<string> GetToken()
|
||||||
{
|
{
|
||||||
var client = new RestClient(_tokenUrl,
|
var client = new RestClient(_tokenUrl, configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));
|
||||||
configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));
|
|
||||||
|
|
||||||
var request = new RestRequest()
|
|
||||||
.AddParameter("grant_type", _grantType)
|
|
||||||
.AddParameter("client_id", _clientId)
|
|
||||||
.AddParameter("client_secret", _clientSecret);
|
|
||||||
|
|
||||||
|
var request = new RestRequest();
|
||||||
|
if (!string.IsNullOrWhiteSpace(_token?.RefreshToken))
|
||||||
|
{
|
||||||
|
request.AddParameter("grant_type", "refresh_token")
|
||||||
|
.AddParameter("refresh_token", _token.RefreshToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
request
|
||||||
|
.AddParameter("grant_type", _grantType)
|
||||||
|
.AddParameter("client_id", _clientId)
|
||||||
|
.AddParameter("client_secret", _clientSecret);
|
||||||
|
}
|
||||||
if (!string.IsNullOrEmpty(_scope))
|
if (!string.IsNullOrEmpty(_scope))
|
||||||
{
|
{
|
||||||
request.AddParameter("scope", _scope);
|
request.AddParameter("scope", _scope);
|
||||||
}
|
}
|
||||||
|
_token = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
|
||||||
var response = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// RFC6749 - token_type is case insensitive.
|
// RFC6749 - token_type is case insensitive.
|
||||||
// RFC6750 - In Authorization header Bearer should be capitalized.
|
// RFC6750 - In Authorization header Bearer should be capitalized.
|
||||||
// Fix the capitalization irrespective of token_type casing.
|
// Fix the capitalization irrespective of token_type casing.
|
||||||
switch (response.TokenType?.ToLower())
|
switch (_token?.TokenType?.ToLower())
|
||||||
{
|
{
|
||||||
case "bearer":
|
case "bearer":
|
||||||
return $"Bearer {response.AccessToken}";
|
return $"Bearer {_token.AccessToken}";
|
||||||
default:
|
default:
|
||||||
return $"{response.TokenType} {response.AccessToken}";
|
return $"{_token?.TokenType} {_token?.AccessToken}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the authentication token (creating a new one if necessary) and adds it to the current request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client"></param>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async ValueTask Authenticate(IRestClient client, RestRequest request)
|
||||||
|
=> request.AddOrUpdateParameter(await GetAuthenticationParameter().ConfigureAwait(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Org.OpenAPITools.Client.Auth
|
namespace Org.OpenAPITools.Client.Auth
|
||||||
@ -18,5 +19,14 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
public string TokenType { get; set; }
|
public string TokenType { get; set; }
|
||||||
[JsonProperty("access_token")]
|
[JsonProperty("access_token")]
|
||||||
public string AccessToken { get; set; }
|
public string AccessToken { get; set; }
|
||||||
|
[JsonProperty("expires_in")]
|
||||||
|
public int? ExpiresIn { get; set; }
|
||||||
|
[JsonProperty("created")]
|
||||||
|
public DateTime? Created { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("refresh_token")]
|
||||||
|
public string RefreshToken { get; set; }
|
||||||
|
|
||||||
|
public DateTime? ExpiresAt => ExpiresIn == null ? null : Created?.AddSeconds(ExpiresIn.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,8 +19,25 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// An authenticator for OAuth2 authentication flows
|
/// An authenticator for OAuth2 authentication flows
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OAuthAuthenticator : AuthenticatorBase
|
public class OAuthAuthenticator : IAuthenticator
|
||||||
{
|
{
|
||||||
|
private TokenResponse _token;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the current authentication token. Can return null if there is no authentication token, or it has expired.
|
||||||
|
/// </summary>
|
||||||
|
public string Token
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_token == null) return null;
|
||||||
|
if (_token.ExpiresIn == null) return _token.AccessToken;
|
||||||
|
if (_token.ExpiresAt < DateTime.Now) return null;
|
||||||
|
|
||||||
|
return _token.AccessToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
readonly string _tokenUrl;
|
readonly string _tokenUrl;
|
||||||
readonly string _clientId;
|
readonly string _clientId;
|
||||||
readonly string _clientSecret;
|
readonly string _clientSecret;
|
||||||
@ -39,7 +56,7 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
string scope,
|
string scope,
|
||||||
OAuthFlow? flow,
|
OAuthFlow? flow,
|
||||||
JsonSerializerSettings serializerSettings,
|
JsonSerializerSettings serializerSettings,
|
||||||
IReadableConfiguration configuration) : base("")
|
IReadableConfiguration configuration)
|
||||||
{
|
{
|
||||||
_tokenUrl = tokenUrl;
|
_tokenUrl = tokenUrl;
|
||||||
_clientId = clientId;
|
_clientId = clientId;
|
||||||
@ -70,9 +87,8 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an authentication parameter from an access token.
|
/// Creates an authentication parameter from an access token.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="accessToken">Access token to create a parameter from.</param>
|
|
||||||
/// <returns>An authentication parameter.</returns>
|
/// <returns>An authentication parameter.</returns>
|
||||||
protected override async ValueTask<Parameter> GetAuthenticationParameter(string accessToken)
|
protected async ValueTask<Parameter> GetAuthenticationParameter()
|
||||||
{
|
{
|
||||||
var token = string.IsNullOrEmpty(Token) ? await GetToken().ConfigureAwait(false) : Token;
|
var token = string.IsNullOrEmpty(Token) ? await GetToken().ConfigureAwait(false) : Token;
|
||||||
return new HeaderParameter(KnownHeaders.Authorization, token);
|
return new HeaderParameter(KnownHeaders.Authorization, token);
|
||||||
@ -84,31 +100,45 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <returns>An authentication token.</returns>
|
/// <returns>An authentication token.</returns>
|
||||||
async Task<string> GetToken()
|
async Task<string> GetToken()
|
||||||
{
|
{
|
||||||
var client = new RestClient(_tokenUrl,
|
var client = new RestClient(_tokenUrl, configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));
|
||||||
configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));
|
|
||||||
|
|
||||||
var request = new RestRequest()
|
|
||||||
.AddParameter("grant_type", _grantType)
|
|
||||||
.AddParameter("client_id", _clientId)
|
|
||||||
.AddParameter("client_secret", _clientSecret);
|
|
||||||
|
|
||||||
|
var request = new RestRequest();
|
||||||
|
if (!string.IsNullOrWhiteSpace(_token?.RefreshToken))
|
||||||
|
{
|
||||||
|
request.AddParameter("grant_type", "refresh_token")
|
||||||
|
.AddParameter("refresh_token", _token.RefreshToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
request
|
||||||
|
.AddParameter("grant_type", _grantType)
|
||||||
|
.AddParameter("client_id", _clientId)
|
||||||
|
.AddParameter("client_secret", _clientSecret);
|
||||||
|
}
|
||||||
if (!string.IsNullOrEmpty(_scope))
|
if (!string.IsNullOrEmpty(_scope))
|
||||||
{
|
{
|
||||||
request.AddParameter("scope", _scope);
|
request.AddParameter("scope", _scope);
|
||||||
}
|
}
|
||||||
|
_token = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
|
||||||
var response = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// RFC6749 - token_type is case insensitive.
|
// RFC6749 - token_type is case insensitive.
|
||||||
// RFC6750 - In Authorization header Bearer should be capitalized.
|
// RFC6750 - In Authorization header Bearer should be capitalized.
|
||||||
// Fix the capitalization irrespective of token_type casing.
|
// Fix the capitalization irrespective of token_type casing.
|
||||||
switch (response.TokenType?.ToLower())
|
switch (_token?.TokenType?.ToLower())
|
||||||
{
|
{
|
||||||
case "bearer":
|
case "bearer":
|
||||||
return $"Bearer {response.AccessToken}";
|
return $"Bearer {_token.AccessToken}";
|
||||||
default:
|
default:
|
||||||
return $"{response.TokenType} {response.AccessToken}";
|
return $"{_token?.TokenType} {_token?.AccessToken}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the authentication token (creating a new one if necessary) and adds it to the current request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client"></param>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async ValueTask Authenticate(IRestClient client, RestRequest request)
|
||||||
|
=> request.AddOrUpdateParameter(await GetAuthenticationParameter().ConfigureAwait(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Org.OpenAPITools.Client.Auth
|
namespace Org.OpenAPITools.Client.Auth
|
||||||
@ -18,5 +19,14 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
public string TokenType { get; set; }
|
public string TokenType { get; set; }
|
||||||
[JsonProperty("access_token")]
|
[JsonProperty("access_token")]
|
||||||
public string AccessToken { get; set; }
|
public string AccessToken { get; set; }
|
||||||
|
[JsonProperty("expires_in")]
|
||||||
|
public int? ExpiresIn { get; set; }
|
||||||
|
[JsonProperty("created")]
|
||||||
|
public DateTime? Created { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("refresh_token")]
|
||||||
|
public string RefreshToken { get; set; }
|
||||||
|
|
||||||
|
public DateTime? ExpiresAt => ExpiresIn == null ? null : Created?.AddSeconds(ExpiresIn.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,8 +19,25 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// An authenticator for OAuth2 authentication flows
|
/// An authenticator for OAuth2 authentication flows
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OAuthAuthenticator : AuthenticatorBase
|
public class OAuthAuthenticator : IAuthenticator
|
||||||
{
|
{
|
||||||
|
private TokenResponse _token;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the current authentication token. Can return null if there is no authentication token, or it has expired.
|
||||||
|
/// </summary>
|
||||||
|
public string Token
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_token == null) return null;
|
||||||
|
if (_token.ExpiresIn == null) return _token.AccessToken;
|
||||||
|
if (_token.ExpiresAt < DateTime.Now) return null;
|
||||||
|
|
||||||
|
return _token.AccessToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
readonly string _tokenUrl;
|
readonly string _tokenUrl;
|
||||||
readonly string _clientId;
|
readonly string _clientId;
|
||||||
readonly string _clientSecret;
|
readonly string _clientSecret;
|
||||||
@ -39,7 +56,7 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
string scope,
|
string scope,
|
||||||
OAuthFlow? flow,
|
OAuthFlow? flow,
|
||||||
JsonSerializerSettings serializerSettings,
|
JsonSerializerSettings serializerSettings,
|
||||||
IReadableConfiguration configuration) : base("")
|
IReadableConfiguration configuration)
|
||||||
{
|
{
|
||||||
_tokenUrl = tokenUrl;
|
_tokenUrl = tokenUrl;
|
||||||
_clientId = clientId;
|
_clientId = clientId;
|
||||||
@ -70,9 +87,8 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an authentication parameter from an access token.
|
/// Creates an authentication parameter from an access token.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="accessToken">Access token to create a parameter from.</param>
|
|
||||||
/// <returns>An authentication parameter.</returns>
|
/// <returns>An authentication parameter.</returns>
|
||||||
protected override async ValueTask<Parameter> GetAuthenticationParameter(string accessToken)
|
protected async ValueTask<Parameter> GetAuthenticationParameter()
|
||||||
{
|
{
|
||||||
var token = string.IsNullOrEmpty(Token) ? await GetToken().ConfigureAwait(false) : Token;
|
var token = string.IsNullOrEmpty(Token) ? await GetToken().ConfigureAwait(false) : Token;
|
||||||
return new HeaderParameter(KnownHeaders.Authorization, token);
|
return new HeaderParameter(KnownHeaders.Authorization, token);
|
||||||
@ -84,31 +100,45 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <returns>An authentication token.</returns>
|
/// <returns>An authentication token.</returns>
|
||||||
async Task<string> GetToken()
|
async Task<string> GetToken()
|
||||||
{
|
{
|
||||||
var client = new RestClient(_tokenUrl,
|
var client = new RestClient(_tokenUrl, configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));
|
||||||
configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));
|
|
||||||
|
|
||||||
var request = new RestRequest()
|
|
||||||
.AddParameter("grant_type", _grantType)
|
|
||||||
.AddParameter("client_id", _clientId)
|
|
||||||
.AddParameter("client_secret", _clientSecret);
|
|
||||||
|
|
||||||
|
var request = new RestRequest();
|
||||||
|
if (!string.IsNullOrWhiteSpace(_token?.RefreshToken))
|
||||||
|
{
|
||||||
|
request.AddParameter("grant_type", "refresh_token")
|
||||||
|
.AddParameter("refresh_token", _token.RefreshToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
request
|
||||||
|
.AddParameter("grant_type", _grantType)
|
||||||
|
.AddParameter("client_id", _clientId)
|
||||||
|
.AddParameter("client_secret", _clientSecret);
|
||||||
|
}
|
||||||
if (!string.IsNullOrEmpty(_scope))
|
if (!string.IsNullOrEmpty(_scope))
|
||||||
{
|
{
|
||||||
request.AddParameter("scope", _scope);
|
request.AddParameter("scope", _scope);
|
||||||
}
|
}
|
||||||
|
_token = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
|
||||||
var response = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// RFC6749 - token_type is case insensitive.
|
// RFC6749 - token_type is case insensitive.
|
||||||
// RFC6750 - In Authorization header Bearer should be capitalized.
|
// RFC6750 - In Authorization header Bearer should be capitalized.
|
||||||
// Fix the capitalization irrespective of token_type casing.
|
// Fix the capitalization irrespective of token_type casing.
|
||||||
switch (response.TokenType?.ToLower())
|
switch (_token?.TokenType?.ToLower())
|
||||||
{
|
{
|
||||||
case "bearer":
|
case "bearer":
|
||||||
return $"Bearer {response.AccessToken}";
|
return $"Bearer {_token.AccessToken}";
|
||||||
default:
|
default:
|
||||||
return $"{response.TokenType} {response.AccessToken}";
|
return $"{_token?.TokenType} {_token?.AccessToken}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the authentication token (creating a new one if necessary) and adds it to the current request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client"></param>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async ValueTask Authenticate(IRestClient client, RestRequest request)
|
||||||
|
=> request.AddOrUpdateParameter(await GetAuthenticationParameter().ConfigureAwait(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Org.OpenAPITools.Client.Auth
|
namespace Org.OpenAPITools.Client.Auth
|
||||||
@ -18,5 +19,14 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
public string TokenType { get; set; }
|
public string TokenType { get; set; }
|
||||||
[JsonProperty("access_token")]
|
[JsonProperty("access_token")]
|
||||||
public string AccessToken { get; set; }
|
public string AccessToken { get; set; }
|
||||||
|
[JsonProperty("expires_in")]
|
||||||
|
public int? ExpiresIn { get; set; }
|
||||||
|
[JsonProperty("created")]
|
||||||
|
public DateTime? Created { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("refresh_token")]
|
||||||
|
public string RefreshToken { get; set; }
|
||||||
|
|
||||||
|
public DateTime? ExpiresAt => ExpiresIn == null ? null : Created?.AddSeconds(ExpiresIn.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,8 +19,25 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// An authenticator for OAuth2 authentication flows
|
/// An authenticator for OAuth2 authentication flows
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OAuthAuthenticator : AuthenticatorBase
|
public class OAuthAuthenticator : IAuthenticator
|
||||||
{
|
{
|
||||||
|
private TokenResponse? _token;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the current authentication token. Can return null if there is no authentication token, or it has expired.
|
||||||
|
/// </summary>
|
||||||
|
public string? Token
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_token == null) return null;
|
||||||
|
if (_token.ExpiresIn == null) return _token.AccessToken;
|
||||||
|
if (_token.ExpiresAt < DateTime.Now) return null;
|
||||||
|
|
||||||
|
return _token.AccessToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
readonly string _tokenUrl;
|
readonly string _tokenUrl;
|
||||||
readonly string _clientId;
|
readonly string _clientId;
|
||||||
readonly string _clientSecret;
|
readonly string _clientSecret;
|
||||||
@ -39,7 +56,7 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
string? scope,
|
string? scope,
|
||||||
OAuthFlow? flow,
|
OAuthFlow? flow,
|
||||||
JsonSerializerSettings serializerSettings,
|
JsonSerializerSettings serializerSettings,
|
||||||
IReadableConfiguration configuration) : base("")
|
IReadableConfiguration configuration)
|
||||||
{
|
{
|
||||||
_tokenUrl = tokenUrl;
|
_tokenUrl = tokenUrl;
|
||||||
_clientId = clientId;
|
_clientId = clientId;
|
||||||
@ -70,9 +87,8 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an authentication parameter from an access token.
|
/// Creates an authentication parameter from an access token.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="accessToken">Access token to create a parameter from.</param>
|
|
||||||
/// <returns>An authentication parameter.</returns>
|
/// <returns>An authentication parameter.</returns>
|
||||||
protected override async ValueTask<Parameter> GetAuthenticationParameter(string accessToken)
|
protected async ValueTask<Parameter> GetAuthenticationParameter()
|
||||||
{
|
{
|
||||||
var token = string.IsNullOrEmpty(Token) ? await GetToken().ConfigureAwait(false) : Token;
|
var token = string.IsNullOrEmpty(Token) ? await GetToken().ConfigureAwait(false) : Token;
|
||||||
return new HeaderParameter(KnownHeaders.Authorization, token);
|
return new HeaderParameter(KnownHeaders.Authorization, token);
|
||||||
@ -84,31 +100,45 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <returns>An authentication token.</returns>
|
/// <returns>An authentication token.</returns>
|
||||||
async Task<string> GetToken()
|
async Task<string> GetToken()
|
||||||
{
|
{
|
||||||
var client = new RestClient(_tokenUrl,
|
var client = new RestClient(_tokenUrl, configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));
|
||||||
configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));
|
|
||||||
|
|
||||||
var request = new RestRequest()
|
|
||||||
.AddParameter("grant_type", _grantType)
|
|
||||||
.AddParameter("client_id", _clientId)
|
|
||||||
.AddParameter("client_secret", _clientSecret);
|
|
||||||
|
|
||||||
|
var request = new RestRequest();
|
||||||
|
if (!string.IsNullOrWhiteSpace(_token?.RefreshToken))
|
||||||
|
{
|
||||||
|
request.AddParameter("grant_type", "refresh_token")
|
||||||
|
.AddParameter("refresh_token", _token.RefreshToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
request
|
||||||
|
.AddParameter("grant_type", _grantType)
|
||||||
|
.AddParameter("client_id", _clientId)
|
||||||
|
.AddParameter("client_secret", _clientSecret);
|
||||||
|
}
|
||||||
if (!string.IsNullOrEmpty(_scope))
|
if (!string.IsNullOrEmpty(_scope))
|
||||||
{
|
{
|
||||||
request.AddParameter("scope", _scope);
|
request.AddParameter("scope", _scope);
|
||||||
}
|
}
|
||||||
|
_token = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
|
||||||
var response = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// RFC6749 - token_type is case insensitive.
|
// RFC6749 - token_type is case insensitive.
|
||||||
// RFC6750 - In Authorization header Bearer should be capitalized.
|
// RFC6750 - In Authorization header Bearer should be capitalized.
|
||||||
// Fix the capitalization irrespective of token_type casing.
|
// Fix the capitalization irrespective of token_type casing.
|
||||||
switch (response.TokenType?.ToLower())
|
switch (_token?.TokenType?.ToLower())
|
||||||
{
|
{
|
||||||
case "bearer":
|
case "bearer":
|
||||||
return $"Bearer {response.AccessToken}";
|
return $"Bearer {_token.AccessToken}";
|
||||||
default:
|
default:
|
||||||
return $"{response.TokenType} {response.AccessToken}";
|
return $"{_token?.TokenType} {_token?.AccessToken}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the authentication token (creating a new one if necessary) and adds it to the current request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client"></param>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async ValueTask Authenticate(IRestClient client, RestRequest request)
|
||||||
|
=> request.AddOrUpdateParameter(await GetAuthenticationParameter().ConfigureAwait(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Org.OpenAPITools.Client.Auth
|
namespace Org.OpenAPITools.Client.Auth
|
||||||
@ -18,5 +19,14 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
public string TokenType { get; set; }
|
public string TokenType { get; set; }
|
||||||
[JsonProperty("access_token")]
|
[JsonProperty("access_token")]
|
||||||
public string AccessToken { get; set; }
|
public string AccessToken { get; set; }
|
||||||
|
[JsonProperty("expires_in")]
|
||||||
|
public int? ExpiresIn { get; set; }
|
||||||
|
[JsonProperty("created")]
|
||||||
|
public DateTime? Created { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("refresh_token")]
|
||||||
|
public string? RefreshToken { get; set; }
|
||||||
|
|
||||||
|
public DateTime? ExpiresAt => ExpiresIn == null ? null : Created?.AddSeconds(ExpiresIn.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,8 +19,25 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// An authenticator for OAuth2 authentication flows
|
/// An authenticator for OAuth2 authentication flows
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OAuthAuthenticator : AuthenticatorBase
|
public class OAuthAuthenticator : IAuthenticator
|
||||||
{
|
{
|
||||||
|
private TokenResponse? _token;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the current authentication token. Can return null if there is no authentication token, or it has expired.
|
||||||
|
/// </summary>
|
||||||
|
public string? Token
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_token == null) return null;
|
||||||
|
if (_token.ExpiresIn == null) return _token.AccessToken;
|
||||||
|
if (_token.ExpiresAt < DateTime.Now) return null;
|
||||||
|
|
||||||
|
return _token.AccessToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
readonly string _tokenUrl;
|
readonly string _tokenUrl;
|
||||||
readonly string _clientId;
|
readonly string _clientId;
|
||||||
readonly string _clientSecret;
|
readonly string _clientSecret;
|
||||||
@ -39,7 +56,7 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
string? scope,
|
string? scope,
|
||||||
OAuthFlow? flow,
|
OAuthFlow? flow,
|
||||||
JsonSerializerSettings serializerSettings,
|
JsonSerializerSettings serializerSettings,
|
||||||
IReadableConfiguration configuration) : base("")
|
IReadableConfiguration configuration)
|
||||||
{
|
{
|
||||||
_tokenUrl = tokenUrl;
|
_tokenUrl = tokenUrl;
|
||||||
_clientId = clientId;
|
_clientId = clientId;
|
||||||
@ -70,9 +87,8 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an authentication parameter from an access token.
|
/// Creates an authentication parameter from an access token.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="accessToken">Access token to create a parameter from.</param>
|
|
||||||
/// <returns>An authentication parameter.</returns>
|
/// <returns>An authentication parameter.</returns>
|
||||||
protected override async ValueTask<Parameter> GetAuthenticationParameter(string accessToken)
|
protected async ValueTask<Parameter> GetAuthenticationParameter()
|
||||||
{
|
{
|
||||||
var token = string.IsNullOrEmpty(Token) ? await GetToken().ConfigureAwait(false) : Token;
|
var token = string.IsNullOrEmpty(Token) ? await GetToken().ConfigureAwait(false) : Token;
|
||||||
return new HeaderParameter(KnownHeaders.Authorization, token);
|
return new HeaderParameter(KnownHeaders.Authorization, token);
|
||||||
@ -84,31 +100,45 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <returns>An authentication token.</returns>
|
/// <returns>An authentication token.</returns>
|
||||||
async Task<string> GetToken()
|
async Task<string> GetToken()
|
||||||
{
|
{
|
||||||
var client = new RestClient(_tokenUrl,
|
var client = new RestClient(_tokenUrl, configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));
|
||||||
configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));
|
|
||||||
|
|
||||||
var request = new RestRequest()
|
|
||||||
.AddParameter("grant_type", _grantType)
|
|
||||||
.AddParameter("client_id", _clientId)
|
|
||||||
.AddParameter("client_secret", _clientSecret);
|
|
||||||
|
|
||||||
|
var request = new RestRequest();
|
||||||
|
if (!string.IsNullOrWhiteSpace(_token?.RefreshToken))
|
||||||
|
{
|
||||||
|
request.AddParameter("grant_type", "refresh_token")
|
||||||
|
.AddParameter("refresh_token", _token.RefreshToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
request
|
||||||
|
.AddParameter("grant_type", _grantType)
|
||||||
|
.AddParameter("client_id", _clientId)
|
||||||
|
.AddParameter("client_secret", _clientSecret);
|
||||||
|
}
|
||||||
if (!string.IsNullOrEmpty(_scope))
|
if (!string.IsNullOrEmpty(_scope))
|
||||||
{
|
{
|
||||||
request.AddParameter("scope", _scope);
|
request.AddParameter("scope", _scope);
|
||||||
}
|
}
|
||||||
|
_token = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
|
||||||
var response = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// RFC6749 - token_type is case insensitive.
|
// RFC6749 - token_type is case insensitive.
|
||||||
// RFC6750 - In Authorization header Bearer should be capitalized.
|
// RFC6750 - In Authorization header Bearer should be capitalized.
|
||||||
// Fix the capitalization irrespective of token_type casing.
|
// Fix the capitalization irrespective of token_type casing.
|
||||||
switch (response.TokenType?.ToLower())
|
switch (_token?.TokenType?.ToLower())
|
||||||
{
|
{
|
||||||
case "bearer":
|
case "bearer":
|
||||||
return $"Bearer {response.AccessToken}";
|
return $"Bearer {_token.AccessToken}";
|
||||||
default:
|
default:
|
||||||
return $"{response.TokenType} {response.AccessToken}";
|
return $"{_token?.TokenType} {_token?.AccessToken}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the authentication token (creating a new one if necessary) and adds it to the current request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client"></param>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async ValueTask Authenticate(IRestClient client, RestRequest request)
|
||||||
|
=> request.AddOrUpdateParameter(await GetAuthenticationParameter().ConfigureAwait(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Org.OpenAPITools.Client.Auth
|
namespace Org.OpenAPITools.Client.Auth
|
||||||
@ -18,5 +19,14 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
public string TokenType { get; set; }
|
public string TokenType { get; set; }
|
||||||
[JsonProperty("access_token")]
|
[JsonProperty("access_token")]
|
||||||
public string AccessToken { get; set; }
|
public string AccessToken { get; set; }
|
||||||
|
[JsonProperty("expires_in")]
|
||||||
|
public int? ExpiresIn { get; set; }
|
||||||
|
[JsonProperty("created")]
|
||||||
|
public DateTime? Created { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("refresh_token")]
|
||||||
|
public string? RefreshToken { get; set; }
|
||||||
|
|
||||||
|
public DateTime? ExpiresAt => ExpiresIn == null ? null : Created?.AddSeconds(ExpiresIn.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,8 +19,25 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// An authenticator for OAuth2 authentication flows
|
/// An authenticator for OAuth2 authentication flows
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OAuthAuthenticator : AuthenticatorBase
|
public class OAuthAuthenticator : IAuthenticator
|
||||||
{
|
{
|
||||||
|
private TokenResponse _token;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the current authentication token. Can return null if there is no authentication token, or it has expired.
|
||||||
|
/// </summary>
|
||||||
|
public string Token
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_token == null) return null;
|
||||||
|
if (_token.ExpiresIn == null) return _token.AccessToken;
|
||||||
|
if (_token.ExpiresAt < DateTime.Now) return null;
|
||||||
|
|
||||||
|
return _token.AccessToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
readonly string _tokenUrl;
|
readonly string _tokenUrl;
|
||||||
readonly string _clientId;
|
readonly string _clientId;
|
||||||
readonly string _clientSecret;
|
readonly string _clientSecret;
|
||||||
@ -39,7 +56,7 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
string scope,
|
string scope,
|
||||||
OAuthFlow? flow,
|
OAuthFlow? flow,
|
||||||
JsonSerializerSettings serializerSettings,
|
JsonSerializerSettings serializerSettings,
|
||||||
IReadableConfiguration configuration) : base("")
|
IReadableConfiguration configuration)
|
||||||
{
|
{
|
||||||
_tokenUrl = tokenUrl;
|
_tokenUrl = tokenUrl;
|
||||||
_clientId = clientId;
|
_clientId = clientId;
|
||||||
@ -70,9 +87,8 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an authentication parameter from an access token.
|
/// Creates an authentication parameter from an access token.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="accessToken">Access token to create a parameter from.</param>
|
|
||||||
/// <returns>An authentication parameter.</returns>
|
/// <returns>An authentication parameter.</returns>
|
||||||
protected override async ValueTask<Parameter> GetAuthenticationParameter(string accessToken)
|
protected async ValueTask<Parameter> GetAuthenticationParameter()
|
||||||
{
|
{
|
||||||
var token = string.IsNullOrEmpty(Token) ? await GetToken().ConfigureAwait(false) : Token;
|
var token = string.IsNullOrEmpty(Token) ? await GetToken().ConfigureAwait(false) : Token;
|
||||||
return new HeaderParameter(KnownHeaders.Authorization, token);
|
return new HeaderParameter(KnownHeaders.Authorization, token);
|
||||||
@ -84,31 +100,45 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <returns>An authentication token.</returns>
|
/// <returns>An authentication token.</returns>
|
||||||
async Task<string> GetToken()
|
async Task<string> GetToken()
|
||||||
{
|
{
|
||||||
var client = new RestClient(_tokenUrl,
|
var client = new RestClient(_tokenUrl, configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));
|
||||||
configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));
|
|
||||||
|
|
||||||
var request = new RestRequest()
|
|
||||||
.AddParameter("grant_type", _grantType)
|
|
||||||
.AddParameter("client_id", _clientId)
|
|
||||||
.AddParameter("client_secret", _clientSecret);
|
|
||||||
|
|
||||||
|
var request = new RestRequest();
|
||||||
|
if (!string.IsNullOrWhiteSpace(_token?.RefreshToken))
|
||||||
|
{
|
||||||
|
request.AddParameter("grant_type", "refresh_token")
|
||||||
|
.AddParameter("refresh_token", _token.RefreshToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
request
|
||||||
|
.AddParameter("grant_type", _grantType)
|
||||||
|
.AddParameter("client_id", _clientId)
|
||||||
|
.AddParameter("client_secret", _clientSecret);
|
||||||
|
}
|
||||||
if (!string.IsNullOrEmpty(_scope))
|
if (!string.IsNullOrEmpty(_scope))
|
||||||
{
|
{
|
||||||
request.AddParameter("scope", _scope);
|
request.AddParameter("scope", _scope);
|
||||||
}
|
}
|
||||||
|
_token = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
|
||||||
var response = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// RFC6749 - token_type is case insensitive.
|
// RFC6749 - token_type is case insensitive.
|
||||||
// RFC6750 - In Authorization header Bearer should be capitalized.
|
// RFC6750 - In Authorization header Bearer should be capitalized.
|
||||||
// Fix the capitalization irrespective of token_type casing.
|
// Fix the capitalization irrespective of token_type casing.
|
||||||
switch (response.TokenType?.ToLower())
|
switch (_token?.TokenType?.ToLower())
|
||||||
{
|
{
|
||||||
case "bearer":
|
case "bearer":
|
||||||
return $"Bearer {response.AccessToken}";
|
return $"Bearer {_token.AccessToken}";
|
||||||
default:
|
default:
|
||||||
return $"{response.TokenType} {response.AccessToken}";
|
return $"{_token?.TokenType} {_token?.AccessToken}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the authentication token (creating a new one if necessary) and adds it to the current request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client"></param>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async ValueTask Authenticate(IRestClient client, RestRequest request)
|
||||||
|
=> request.AddOrUpdateParameter(await GetAuthenticationParameter().ConfigureAwait(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Org.OpenAPITools.Client.Auth
|
namespace Org.OpenAPITools.Client.Auth
|
||||||
@ -18,5 +19,14 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
public string TokenType { get; set; }
|
public string TokenType { get; set; }
|
||||||
[JsonProperty("access_token")]
|
[JsonProperty("access_token")]
|
||||||
public string AccessToken { get; set; }
|
public string AccessToken { get; set; }
|
||||||
|
[JsonProperty("expires_in")]
|
||||||
|
public int? ExpiresIn { get; set; }
|
||||||
|
[JsonProperty("created")]
|
||||||
|
public DateTime? Created { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("refresh_token")]
|
||||||
|
public string RefreshToken { get; set; }
|
||||||
|
|
||||||
|
public DateTime? ExpiresAt => ExpiresIn == null ? null : Created?.AddSeconds(ExpiresIn.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,8 +19,25 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// An authenticator for OAuth2 authentication flows
|
/// An authenticator for OAuth2 authentication flows
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OAuthAuthenticator : AuthenticatorBase
|
public class OAuthAuthenticator : IAuthenticator
|
||||||
{
|
{
|
||||||
|
private TokenResponse _token;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the current authentication token. Can return null if there is no authentication token, or it has expired.
|
||||||
|
/// </summary>
|
||||||
|
public string Token
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_token == null) return null;
|
||||||
|
if (_token.ExpiresIn == null) return _token.AccessToken;
|
||||||
|
if (_token.ExpiresAt < DateTime.Now) return null;
|
||||||
|
|
||||||
|
return _token.AccessToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
readonly string _tokenUrl;
|
readonly string _tokenUrl;
|
||||||
readonly string _clientId;
|
readonly string _clientId;
|
||||||
readonly string _clientSecret;
|
readonly string _clientSecret;
|
||||||
@ -39,7 +56,7 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
string scope,
|
string scope,
|
||||||
OAuthFlow? flow,
|
OAuthFlow? flow,
|
||||||
JsonSerializerSettings serializerSettings,
|
JsonSerializerSettings serializerSettings,
|
||||||
IReadableConfiguration configuration) : base("")
|
IReadableConfiguration configuration)
|
||||||
{
|
{
|
||||||
_tokenUrl = tokenUrl;
|
_tokenUrl = tokenUrl;
|
||||||
_clientId = clientId;
|
_clientId = clientId;
|
||||||
@ -70,9 +87,8 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an authentication parameter from an access token.
|
/// Creates an authentication parameter from an access token.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="accessToken">Access token to create a parameter from.</param>
|
|
||||||
/// <returns>An authentication parameter.</returns>
|
/// <returns>An authentication parameter.</returns>
|
||||||
protected override async ValueTask<Parameter> GetAuthenticationParameter(string accessToken)
|
protected async ValueTask<Parameter> GetAuthenticationParameter()
|
||||||
{
|
{
|
||||||
var token = string.IsNullOrEmpty(Token) ? await GetToken().ConfigureAwait(false) : Token;
|
var token = string.IsNullOrEmpty(Token) ? await GetToken().ConfigureAwait(false) : Token;
|
||||||
return new HeaderParameter(KnownHeaders.Authorization, token);
|
return new HeaderParameter(KnownHeaders.Authorization, token);
|
||||||
@ -84,31 +100,45 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
/// <returns>An authentication token.</returns>
|
/// <returns>An authentication token.</returns>
|
||||||
async Task<string> GetToken()
|
async Task<string> GetToken()
|
||||||
{
|
{
|
||||||
var client = new RestClient(_tokenUrl,
|
var client = new RestClient(_tokenUrl, configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));
|
||||||
configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));
|
|
||||||
|
|
||||||
var request = new RestRequest()
|
|
||||||
.AddParameter("grant_type", _grantType)
|
|
||||||
.AddParameter("client_id", _clientId)
|
|
||||||
.AddParameter("client_secret", _clientSecret);
|
|
||||||
|
|
||||||
|
var request = new RestRequest();
|
||||||
|
if (!string.IsNullOrWhiteSpace(_token?.RefreshToken))
|
||||||
|
{
|
||||||
|
request.AddParameter("grant_type", "refresh_token")
|
||||||
|
.AddParameter("refresh_token", _token.RefreshToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
request
|
||||||
|
.AddParameter("grant_type", _grantType)
|
||||||
|
.AddParameter("client_id", _clientId)
|
||||||
|
.AddParameter("client_secret", _clientSecret);
|
||||||
|
}
|
||||||
if (!string.IsNullOrEmpty(_scope))
|
if (!string.IsNullOrEmpty(_scope))
|
||||||
{
|
{
|
||||||
request.AddParameter("scope", _scope);
|
request.AddParameter("scope", _scope);
|
||||||
}
|
}
|
||||||
|
_token = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
|
||||||
var response = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// RFC6749 - token_type is case insensitive.
|
// RFC6749 - token_type is case insensitive.
|
||||||
// RFC6750 - In Authorization header Bearer should be capitalized.
|
// RFC6750 - In Authorization header Bearer should be capitalized.
|
||||||
// Fix the capitalization irrespective of token_type casing.
|
// Fix the capitalization irrespective of token_type casing.
|
||||||
switch (response.TokenType?.ToLower())
|
switch (_token?.TokenType?.ToLower())
|
||||||
{
|
{
|
||||||
case "bearer":
|
case "bearer":
|
||||||
return $"Bearer {response.AccessToken}";
|
return $"Bearer {_token.AccessToken}";
|
||||||
default:
|
default:
|
||||||
return $"{response.TokenType} {response.AccessToken}";
|
return $"{_token?.TokenType} {_token?.AccessToken}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the authentication token (creating a new one if necessary) and adds it to the current request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client"></param>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async ValueTask Authenticate(IRestClient client, RestRequest request)
|
||||||
|
=> request.AddOrUpdateParameter(await GetAuthenticationParameter().ConfigureAwait(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Org.OpenAPITools.Client.Auth
|
namespace Org.OpenAPITools.Client.Auth
|
||||||
@ -18,5 +19,14 @@ namespace Org.OpenAPITools.Client.Auth
|
|||||||
public string TokenType { get; set; }
|
public string TokenType { get; set; }
|
||||||
[JsonProperty("access_token")]
|
[JsonProperty("access_token")]
|
||||||
public string AccessToken { get; set; }
|
public string AccessToken { get; set; }
|
||||||
|
[JsonProperty("expires_in")]
|
||||||
|
public int? ExpiresIn { get; set; }
|
||||||
|
[JsonProperty("created")]
|
||||||
|
public DateTime? Created { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("refresh_token")]
|
||||||
|
public string RefreshToken { get; set; }
|
||||||
|
|
||||||
|
public DateTime? ExpiresAt => ExpiresIn == null ? null : Created?.AddSeconds(ExpiresIn.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user