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 auth token refresh to csharp #20234

Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,25 @@ namespace {{packageName}}.Client.Auth
/// <summary>
/// An authenticator for OAuth2 authentication flows
/// </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 _clientId;
readonly string _clientSecret;
Expand All @@ -31,7 +48,7 @@ namespace {{packageName}}.Client.Auth
string{{nrt?}} scope,
OAuthFlow? flow,
JsonSerializerSettings serializerSettings,
IReadableConfiguration configuration) : base("")
IReadableConfiguration configuration)
{
_tokenUrl = tokenUrl;
_clientId = clientId;
Expand Down Expand Up @@ -62,9 +79,8 @@ namespace {{packageName}}.Client.Auth
/// <summary>
/// Creates an authentication parameter from an access token.
/// </summary>
/// <param name="accessToken">Access token to create a parameter from.</param>
/// <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;
return new HeaderParameter(KnownHeaders.Authorization, token);
Expand All @@ -76,31 +92,45 @@ namespace {{packageName}}.Client.Auth
/// <returns>An authentication token.</returns>
async Task<string> GetToken()
{
var client = new RestClient(_tokenUrl,
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 client = new RestClient(_tokenUrl, configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));

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))
{
request.AddParameter("scope", _scope);
}

var response = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);

_token = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
// RFC6749 - token_type is case insensitive.
// RFC6750 - In Authorization header Bearer should be capitalized.
// Fix the capitalization irrespective of token_type casing.
switch (response.TokenType?.ToLower())
switch (_token?.TokenType?.ToLower())
{
case "bearer":
return $"Bearer {response.AccessToken}";
return $"Bearer {_token.AccessToken}";
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));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{{>partial_header}}

using System;
using Newtonsoft.Json;

namespace {{packageName}}.Client.Auth
Expand All @@ -10,5 +11,14 @@ namespace {{packageName}}.Client.Auth
public string TokenType { get; set; }
[JsonProperty("access_token")]
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,25 @@ namespace Org.OpenAPITools.Client.Auth
/// <summary>
/// An authenticator for OAuth2 authentication flows
/// </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 _clientId;
readonly string _clientSecret;
Expand All @@ -39,7 +56,7 @@ public OAuthAuthenticator(
string scope,
OAuthFlow? flow,
JsonSerializerSettings serializerSettings,
IReadableConfiguration configuration) : base("")
IReadableConfiguration configuration)
{
_tokenUrl = tokenUrl;
_clientId = clientId;
Expand Down Expand Up @@ -70,9 +87,8 @@ public OAuthAuthenticator(
/// <summary>
/// Creates an authentication parameter from an access token.
/// </summary>
/// <param name="accessToken">Access token to create a parameter from.</param>
/// <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;
return new HeaderParameter(KnownHeaders.Authorization, token);
Expand All @@ -84,31 +100,45 @@ protected override async ValueTask<Parameter> GetAuthenticationParameter(string
/// <returns>An authentication token.</returns>
async Task<string> GetToken()
{
var client = new RestClient(_tokenUrl,
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 client = new RestClient(_tokenUrl, configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));

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))
{
request.AddParameter("scope", _scope);
}

var response = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);

_token = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
// RFC6749 - token_type is case insensitive.
// RFC6750 - In Authorization header Bearer should be capitalized.
// Fix the capitalization irrespective of token_type casing.
switch (response.TokenType?.ToLower())
switch (_token?.TokenType?.ToLower())
{
case "bearer":
return $"Bearer {response.AccessToken}";
return $"Bearer {_token.AccessToken}";
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));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/


using System;
using Newtonsoft.Json;

namespace Org.OpenAPITools.Client.Auth
Expand All @@ -18,5 +19,14 @@ class TokenResponse
public string TokenType { get; set; }
[JsonProperty("access_token")]
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,25 @@ namespace Org.OpenAPITools.Client.Auth
/// <summary>
/// An authenticator for OAuth2 authentication flows
/// </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 _clientId;
readonly string _clientSecret;
Expand All @@ -39,7 +56,7 @@ public OAuthAuthenticator(
string scope,
OAuthFlow? flow,
JsonSerializerSettings serializerSettings,
IReadableConfiguration configuration) : base("")
IReadableConfiguration configuration)
{
_tokenUrl = tokenUrl;
_clientId = clientId;
Expand Down Expand Up @@ -70,9 +87,8 @@ public OAuthAuthenticator(
/// <summary>
/// Creates an authentication parameter from an access token.
/// </summary>
/// <param name="accessToken">Access token to create a parameter from.</param>
/// <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;
return new HeaderParameter(KnownHeaders.Authorization, token);
Expand All @@ -84,31 +100,45 @@ protected override async ValueTask<Parameter> GetAuthenticationParameter(string
/// <returns>An authentication token.</returns>
async Task<string> GetToken()
{
var client = new RestClient(_tokenUrl,
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 client = new RestClient(_tokenUrl, configureSerialization: serializerConfig => serializerConfig.UseSerializer(() => new CustomJsonCodec(_serializerSettings, _configuration)));

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))
{
request.AddParameter("scope", _scope);
}

var response = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);

_token = await client.PostAsync<TokenResponse>(request).ConfigureAwait(false);
// RFC6749 - token_type is case insensitive.
// RFC6750 - In Authorization header Bearer should be capitalized.
// Fix the capitalization irrespective of token_type casing.
switch (response.TokenType?.ToLower())
switch (_token?.TokenType?.ToLower())
{
case "bearer":
return $"Bearer {response.AccessToken}";
return $"Bearer {_token.AccessToken}";
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));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/


using System;
using Newtonsoft.Json;

namespace Org.OpenAPITools.Client.Auth
Expand All @@ -18,5 +19,14 @@ class TokenResponse
public string TokenType { get; set; }
[JsonProperty("access_token")]
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
Loading