Skip to content

Commit

Permalink
Merge pull request #126 from jinaga/revoke-token
Browse files Browse the repository at this point in the history
Revoke the token on logout
  • Loading branch information
michaellperry authored Jul 14, 2024
2 parents b8fd0b5 + 086ca38 commit a8ed53e
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 5 deletions.
15 changes: 11 additions & 4 deletions Jinaga.Maui/Authentication/AuthenticationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ public async Task LogOut()
return;
}

await InvalidateToken(cachedAuthenticationToken).ConfigureAwait(false);
await RevokeToken(cachedAuthenticationToken).ConfigureAwait(false);
lock (stateLock)
{
authenticationState = AuthenticationResult.Empty;
Expand Down Expand Up @@ -270,10 +270,17 @@ private async Task<AuthenticationResult> Authenticate(string provider)
return token;
}

private Task InvalidateToken(AuthenticationToken cachedAuthenticationToken)
private async Task RevokeToken(AuthenticationToken cachedAuthenticationToken)
{
// TODO: Implement token invalidation.
return Task.CompletedTask;
try
{
await oauthClient.RevokeToken(cachedAuthenticationToken.AccessToken, cachedAuthenticationToken.RefreshToken).ConfigureAwait(false);
logger.LogInformation("Revoked token");
}
catch (Exception ex)
{
logger.LogError(ex, "Failed to revoke token");
}
}

private static bool IsExpired(AuthenticationToken token)
Expand Down
4 changes: 3 additions & 1 deletion Jinaga.Maui/Authentication/AuthenticationSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
namespace Jinaga.Maui.Authentication;
public class AuthenticationSettings
{
public AuthenticationSettings(ImmutableDictionary<string, string> authUrlByProvider, string accessTokenUrl, string callbackUrl, string clientId, string scope, Func<JinagaClient, User, UserProfile, Task> updateUserName)
public AuthenticationSettings(ImmutableDictionary<string, string> authUrlByProvider, string accessTokenUrl, string revokeUrl, string callbackUrl, string clientId, string scope, Func<JinagaClient, User, UserProfile, Task> updateUserName)
{
AuthUrlByProvider = authUrlByProvider;
AccessTokenUrl = accessTokenUrl;
RevokeUrl = revokeUrl;
CallbackUrl = callbackUrl;
ClientId = clientId;
Scope = scope;
Expand All @@ -15,6 +16,7 @@ public AuthenticationSettings(ImmutableDictionary<string, string> authUrlByProvi

public ImmutableDictionary<string, string> AuthUrlByProvider { get; }
public string AccessTokenUrl { get; }
public string RevokeUrl { get; }
public string CallbackUrl { get; }
public string ClientId { get; }
public string Scope { get; }
Expand Down
33 changes: 33 additions & 0 deletions Jinaga.Maui/Authentication/OAuthClient.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.Immutable;
using System.Net;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
Expand All @@ -10,6 +11,7 @@ public class OAuthClient
{
private readonly ImmutableDictionary<string, string> authUrlByProvider;
private readonly string accessTokenUrl;
private readonly string revokeUrl;
private readonly string callbackUrl;
private readonly string clientId;
private readonly string scope;
Expand All @@ -25,6 +27,7 @@ public OAuthClient(AuthenticationSettings authenticationSettings, IHttpClientFac
{
authUrlByProvider = authenticationSettings.AuthUrlByProvider;
accessTokenUrl = authenticationSettings.AccessTokenUrl;
revokeUrl = authenticationSettings.RevokeUrl;
callbackUrl = authenticationSettings.CallbackUrl;
clientId = authenticationSettings.ClientId;
scope = authenticationSettings.Scope;
Expand Down Expand Up @@ -144,6 +147,36 @@ public async Task<TokenResponse> GetTokenResponse(string code)
return token;
}

public async Task RevokeToken(string accessToken, string refreshToken)
{
var requestBody = new FormUrlEncodedContent(
[
new KeyValuePair<string, string>("token", refreshToken),
new KeyValuePair<string, string>("token_type_hint", "refresh_token")
]);

var request = new HttpRequestMessage(HttpMethod.Post, revokeUrl);
request.Content = requestBody;
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

var client = httpClientFactory.CreateClient();
client.Timeout = TimeSpan.FromSeconds(30);
var response = await client.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
string errorContent;
try
{
errorContent = await response.Content.ReadAsStringAsync();
throw new Exception($"Failed to revoke the token: {(int)response.StatusCode} {response.ReasonPhrase}: {errorContent}");
}
catch (Exception)
{
throw new Exception($"Failed to revoke the token: {(int)response.StatusCode} {response.ReasonPhrase}");
}
}
}

private static string GenerateRandomString()
{
var randomBytes = RandomNumberGenerator.GetBytes(32);
Expand Down

0 comments on commit a8ed53e

Please sign in to comment.