Reputation: 65
I have a Razor Pages app developed using .NET Core 6. The app works as a client and connects to an API. The API has JWT Access Token/Refresh Token authentication. The login endpoint of the API returns access token and refresh token.Using cookie authentication I store the tokens as claim in authentication cookie.
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, Login.Email),
new Claim("Token", loginResponse.Token),
new Claim("RefreshToken", loginResponse.RefreshToken)
};
I then get the tokens using extension methods
public static class CommonExtensions
{
public static string? GetToken(this HttpContext context)
{
return context.User.Claims.Single(x => x.Type == "Token").Value.ToString();
}
public static string? GetRefreshToken(this HttpContext context)
{
return context.User.Claims.Single(x => x.Type == "RefreshToken").Value.ToString();
}
}
When my access token expires I refresh it, remove existing claims and add new ones with the updated token.
var identity = User.Identity as ClaimsIdentity;
identity.RemoveClaim(identity.FindFirst("Token"));
identity.AddClaim(new Claim("Token", response.Token));
identity.RemoveClaim(identity.FindFirst("RefreshToken"));
identity.AddClaim(new Claim("RefreshToken", response.RefreshToken));
However the subsequent requests keep using the expired token. What is the way to update the claims correctly?
Upvotes: 1
Views: 4731
Reputation: 31
Implement the CookieAuthenticationEvents
, and you can update the Principal when you validate it.
using Microsoft.AspNetCore.Authentication.Cookies;
public class CustomCookieAuthenticationEvents
: CookieAuthenticationEvents
{
...
public override Task ValidatePrincipal(CookieValidatePrincipalContext context)
{
...
if (needToUpdateCookie)
{
var identity = User.Identity as ClaimsIdentity;
identity.RemoveClaim(identity.FindFirst("Token"));
identity.AddClaim(new Claim("Token", response.Token));
identity.RemoveClaim(identity.FindFirst("RefreshToken"));
identity.AddClaim(new Claim("RefreshToken", response.RefreshToken));
context.ShouldRenew = true;
}
...
}
...
}
In your bootstrap...
// Off course you can inject the dependencies to CostomCookieAuthenticationEvents...
builder.Services.AddScope<CustomCookieAuthenticationEvents>();
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
...
options.EventsType = typeof(CustomCookieAuthenticationEvents);
...
});
Upvotes: 3