Home > Net >  Role from JWT 401 unauthorized while using Authorized on controller
Role from JWT 401 unauthorized while using Authorized on controller

Time:01-20

I'm getting 401 unauthorized while using GET with JWT in header. For single role authorized doesn't work as well.

SecurityService.cs - Generated random key on creation. Role is taken from user instance.

private const int TokenExpirationInSeconds = 600;
private readonly IConfiguration _configuration;
public byte[] Key { get; } = RandomNumberGenerator.GetBytes(128);
public string BuildJwtToken(User user)
    {
        var roles = new List<Role> {user.Role};
        var roleClaims = roles.ToDictionary(
            q => ClaimTypes.Role,
            q => (object) q.Name.ToUpper());

        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new[]
            {
                new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
                new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName),
                new Claim(JwtRegisteredClaimNames.Aud, _configuration["Jwt:Audience"] ?? string.Empty),
                new Claim(JwtRegisteredClaimNames.Iss, _configuration["Jwt:Issuer"] ?? string.Empty),
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
            }),
            Expires = DateTime.UtcNow.AddSeconds(TokenExpirationInSeconds),
            SigningCredentials =
                new SigningCredentials(new SymmetricSecurityKey(Key), SecurityAlgorithms.HmacSha512Signature),
            Claims = roleClaims
        };

        var tokenHandler = new JwtSecurityTokenHandler();
        var token = tokenHandler.CreateToken(tokenDescriptor);
        var ret = tokenHandler.WriteToken(token);

        return ret;
    }

Program.cs - SecurityService is added as singleton. Authentication, authorization used.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton<IConfiguration>(builder.Configuration);
SecurityService securityService = new(builder.Configuration);
builder.Services.AddDbContext<WorkItDbContext>();
builder.Services.AddSingleton<SecurityService>();
builder.Services.AddTransient<UserService>();
builder.Services.AddTransient<RoleService>();
builder.Services.AddTransient<OfferService>();
builder.Services.AddTransient<CategoryService>();
builder.Services.AddTransient<ResponseService>();
builder.Services.AddTransient<LocationService>();
builder.Services.AddCors();

builder.Services.AddControllers().AddNewtonsoftJson(options =>
    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
builder.Services.AddAuthorization();
builder.Services.AddAuthentication(opt =>
{
    opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    opt.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(opt =>
{
    var key = new SymmetricSecurityKey(securityService.Key);
    opt.TokenValidationParameters = new TokenValidationParameters()
    {
        IssuerSigningKey = key,
        ValidateIssuer = false,
        ValidateAudience = false,
        ValidateIssuerSigningKey = true,
        ValidateLifetime = true,
        ClockSkew = TimeSpan.Zero
    };
});

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseSwagger();
app.UseSwaggerUI();


app.UseCors(options =>
    options.WithOrigins("http://localhost:4200/").AllowAnyMethod().AllowAnyHeader().AllowAnyOrigin());
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

CustomRoles.cs

public static class CustomRoles
{
    public const string Admin = "ADMIN";
    public const string Recruiter = "RECUITER";
    public const string User = "USER";
}

UserController.cs

[HttpGet("All")]
[Authorize(Roles = CustomRoles.Admin   ","   CustomRoles.User   ","   CustomRoles.Recruiter)]
public async Task<IActionResult> GetUsers()
{
    return Ok(await _userService.GetUsers());
}

Role.cs

public class Role
{
    public Role()
    {
        Users = new HashSet<User>();
    }

    public long RoleId { get; set; }
    public string? Name { get; set; }

    public virtual ICollection<User> Users { get; set; }
}

Images

JWT

Response

Entering JWT into GET

CodePudding user response:

I reproduced your issue about the 401 error.

enter image description here

In my side it's related with the SigningCredentials defined in the SecurityService and the IssuerSigningKey defined in Program.cs.

You used RandomNumberGenerator.GetBytes(128) to generate a Key and use it to set SigningCredentials and define the IssuerSigningKey. And when I used a hardcode Key, it worked for me.

I used IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("ThisismySecretKey")) in the Program.cs and SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes("ThisismySecretKey")), SecurityAlgorithms.HmacSha512Signature) in SecurityService.

enter image description here

Therefore, I compared the value of the key used in Program.cs and SecurityService, I found they don't have the same value. So I recommend you trying to hardcode the key first for testing, then check if it worked for you.

enter image description here

  • Related