Implementing JWT Token Authorization in .NET 8 using AddJwtBearer() with a Custom Role Based Attributes

74 views Asked by At

I receive a bearer JWT access token from my SPA and I need to validate this JWT token but also use the role claim inside it. The role claim currently uses the field "user-roles" : "admin,usertype2". So the types of roles are comma delimited in the "user-roles" (I may be able to have our Okta team change it to a string array if this is easier but currently this is the implementation). I have already built a custom attribute to try and handle authorization but I want to use the standard MS libraries to make this work. I have the following in my program.cs:

builder.Services.AddAuthentication().AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        RoleClaimType = "user-roles"
    };
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseRateLimiter();
app.UseStaticFiles();
app.UseCors("MyPolicy");
app.UseAuthorization();
app.MapControllers();

app.Run(); 

Then for my implementation I was trying the following:

    [HttpGet(Name = "GetUserAccount")]
    [Authorize(Roles = "usertype1,usertype2")]
    [EnableRateLimiting("api")]
    public IActionResult Get()
    {
        User TestAccount = new User() {InternalUserNumber = 3, EmailAddress = "[email protected]"};
        var json = _userAccountService.Read(TestAccount);
        return Ok(json);
    }

I thought setting RoleClaimType = "user-roles"in the options for the AddJwtBearer() function would allow set the custom field in the claims to look for but it doesnt seem to do that. I am not sure how to set the custom role field and its also not clear how I can get the string to split() so it can check for an intersect that these roles are actually in the claims.

1

There are 1 answers

0
Qiuzman On

In order to implement a claims check with AddJwtBearer() on validation using an attribute the following will work:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.IdentityModel.Tokens;

namespace APP_API.Filters
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class OktaAllowedRoles : Attribute, IAuthorizationFilter
    {
        private readonly string[] _allowedRoles;
        public OktaAllowedRoles(string[] AllowedRoles)
        {
            _allowedRoles = AllowedRoles;
        }
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            var claim = context.HttpContext.User.Claims.Where(claim => claim.Type.ToString() == "roles").FirstOrDefault();

            if(claim == null){
               context.Result = new UnauthorizedObjectResult(string.Empty);
               return;
            }
            else{
                var ClaimRoles =  claim.Value.Split(',');
                if(ClaimRoles.Intersect(_allowedRoles!).ToArray().IsNullOrEmpty())
                {
                    context.Result = new UnauthorizedObjectResult(string.Empty);
                    return;
                }
            }
        }
    }
}