Vaccano
Vaccano

Reputation: 82341

Have two Claims Identities in the User (ClaimsPrincipal) with Only One Used for [Authorize]

I have two JWTs that are included in all the calls to my service. The first one (called UserJwt) is the one that I want to be used for [Authorize] for most service operations. The second one (called ApplicationJwt) has useful information that I would also like to be in the User.Identities list of ClaimsIdentity objects.

I setup my code so that the UserJwt is always used and the ApplicationJwt is ignored:

services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(options =>
    {
        // Setup the JWT stuff here for the UserJwt         
    })

This works fine, but but I want both JWTs parsed and put into the User.Identities list.

I tried setting up my code to follow this answer, (to the question: Use multiple JWT Bearer Authentication) but this allows either one (UserJwt or ApplicationJwt).

At worst I need it to require both. However, I prefer it to only require UserJwt but include ApplicationJwt as a ClaimsIdentity if found.

    services.AddAuthentication()
        .AddJwtBearer("UserJwt", options =>
        {
            // Setup the JWT stuff here for the UserJwt
        })
        .AddJwtBearer("ApplicationJwt", options =>
         {
             // Setup the JWT stuff here for the ApplicationJwt
         });

    services.AddAuthorization(options =>
    {
        options.DefaultPolicy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .AddAuthenticationSchemes("UserJwt", "ApplicationJwt")
            .Build();
    });

How can I get both JWTs to be in the User.Identities list, have the UserJwt be the one that is used for [Authorize], but also allow [Authorize(Policy = "ApplicationJwt")] on some service operations?

Upvotes: 2

Views: 953

Answers (1)

weichch
weichch

Reputation: 10035

One option here is adding custom requirements to default policy.

Assume UserJwt contains specific claims:

options.DefaultPolicy = new AuthorizationPolicyBuilder()
    .AddAuthenticationSchemes("UserJwt", "ApplicationJwt")
    .RequireAuthenticatedUser()
    .AddRequirements(
        // Assume UserJwt contains a AuthenticationMethod claim where 
        // value is equal to User
        new ClaimsAuthorizationRequirement(
            ClaimTypes.AuthenticationMethod, new[] { "User" }
        )
    )
    .Build();

Also see other built-in requirement types.

Note that when requirement is not met, user is still authenticated but denied access. To handle forbidden scenario, use JwtBearerEvents.OnForbidden event:

OnForbidden = async context =>
{
    context.Response.StatusCode = 401;
}

Upvotes: 1

Related Questions