Divyang Vyas
Divyang Vyas

Reputation: 65

How to update user claims stored in authentication cookie in .NET Core 6

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

Answers (2)

MASHER
MASHER

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

Mihail
Mihail

Reputation: 823

In order to save your changes you would need to call SignInAsync according to Microsoft.

await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, User);

If it does not work, maybe you need to call SignOutAsync first.

Upvotes: 1

Related Questions