ASP.Net Core 3.0 JWT Bearer Token No SecurityTokenValidator available

15,009

Solution 1

Try to use ClaimTypes.Role instead of roles if you want to add a Role as claim.

var tokeOptions = new JwtSecurityToken(
                            issuer: "http://localhost:44352",
                            audience: "http://localhost:44352",
                            claims: new List<Claim>(new List<Claim> {
                                    new Claim("userName",cred.userName),
                                    new Claim(ClaimTypes.Role, "Admin")                                      
                            }),
                            expires: DateTime.Now.AddHours(1),
                            signingCredentials: signinCredentials
                );

Solution 2

Thanks to Xing Zou, I got to the root of the error. The problem was that I sent the bearer token with quotation marks.

Request

The error in the API now is gone, the problem is that the authorization now fails in the API and it returns 403.

EDIT:

I found the issue concerning error 403. It seems that you are only allowed to send ONE role in the bearer token for ASP.Net to validate it. The return type of userManager.GetRolesAsync suggests that a user can have multiple roles which can be included in a JWT bearer token.

That means my issue is fixed.

I want to thank everybody for their answers. I would not have gotten it without you!

Share:
15,009
Dieter Köberl
Author by

Dieter Köberl

Updated on June 05, 2022

Comments

  • Dieter Köberl
    Dieter Köberl almost 2 years

    I am using a ASP.Net Core 3.0 API with EntityFramework Core as UserStorage. Startup.cs:

            public void ConfigureServices(IServiceCollection services)
                {
                 using Microsoft.AspNetCore.Authentication.JwtBearer;
                 using Microsoft.AspNetCore.Builder;
                 using Microsoft.AspNetCore.Hosting;
                 using Microsoft.AspNetCore.Identity;
                 using Microsoft.AspNetCore.SpaServices.AngularCli;
                 using Microsoft.EntityFrameworkCore;
                 using Microsoft.Extensions.Configuration;
                 using Microsoft.Extensions.DependencyInjection;
                 using Microsoft.Extensions.Hosting;
                 using Microsoft.IdentityModel.Tokens;
                 using System;
                 using System.Collections.Generic;
                 using System.Linq;
                 using System.Text;
                 using System.Threading.Tasks;
                    .
                    .
                    .
    
                    //Add Identity Provider with EntityFramework
                    services.AddIdentity<User, IdentityRole>()
                    .AddEntityFrameworkStores<ApplicationDBContext>()
                    .AddDefaultTokenProviders();
    
                    //Initialize EntityFramework
                    services.AddDbContext<ApplicationDBContext>(options => options.UseSqlite(Configuration.GetConnectionString("localDB")));
    
                    //Initialize JWT Authentication
                    services.AddAuthentication(options => {
                        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                    }).AddJwtBearer(jwtBearerOptions =>
                    {
                        jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters()
                        {
                            ValidateIssuer = true,
                            ValidateAudience = true,
                            ValidateLifetime = true,
                            ValidateIssuerSigningKey = true,
    
                            ValidIssuer = "http://localhost:44352",
                            ValidAudience = "http://localhost:44352",
                            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetSection("Secrets")["jwt"]))
                        };
                    }
                    );
                    services.AddMvc(options => options.EnableEndpointRouting = false)
                        .AddNewtonsoftJson();
    
                    // In production, the Angular files will be served from this directory
                    services.AddSpaStaticFiles(configuration =>
                    {
                        configuration.RootPath = "ClientApp/dist";
                    });
                }
    
                .
                .
                .
    
    
                    app.UseHttpsRedirection();
                    app.UseStaticFiles();
                    app.UseSpaStaticFiles();
    
                    //Enable Authentication
                    app.UseAuthentication();
                    app.UseAuthorization();
    
                    .
                    .
                    .
    
                    app.UseMvc(routes =>
                    {
                        routes.MapRoute(
                            name: "default",
                            template: "{controller}/{action=Index}/{id?}");
                    });
    
    
        .
        .
        .
    

    This is my code issuing a JWT token:

    
    public async Task<IActionResult> Login()
            {
                using (var reader = new StreamReader(Request.Body))
                {
                    var body = await reader.ReadToEndAsync();
                    var cred = JsonConvert.DeserializeObject<Credentials>(body);
                    var result = (await userService.LoginUser(cred.userName, cred.password));
                    if (result == 200)
                    {
    
                        var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration.GetSection("Secrets")["jwt"]));
                        var signinCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256Signature);
    
                        var roles = await userService.GetRoleFromUsername(cred.userName);
                        var rolesString = JsonConvert.SerializeObject(roles);
    
                        var tokeOptions = new JwtSecurityToken(
                                    issuer: "http://localhost:44352",
                                    audience: "http://localhost:44352",
                                    claims: new List<Claim>(new List<Claim> {
                                            new Claim("userName",cred.userName),
                                            new Claim("roles", rolesString)
                                    }),
                                    expires: DateTime.Now.AddHours(1),
                                    signingCredentials: signinCredentials
                        );
    
    

    This is my API call using Authorization:

    
    [Route("api/videos/add")]
    [Authorize(Roles = "Admin")]
    [HttpPost]
    public async Task<IActionResult> AddVideo()
    {
        using (var reader = new StreamReader(Request.Body))
        {
            var body = await reader.ReadToEndAsync();
            var video = JsonConvert.DeserializeObject<Video>(body);
            await videoService.AddVideo(video);
            return Ok();
        }
    }
    
    

    My NuGet Packages are:

    • Microsoft.EntityFrameworkCore {3.0.0-preview5.19227.1}
    • Microsoft.EntityFrameworkCore.Sqlite {3.0.0-preview5.19227.1}
    • Microsoft.AspNetCore.Authentication.JwtBearer {3.0.0-preview4-19216-03}
    • Microsoft.EntityFrameworkCore.Sqlite.Core {3.0.0-preview5.19227.1}
    • Microsoft.NETCore.Platforms {3.0.0-preview4.19212.13}
    • Microsoft.AspNetCore.Mvc.NewtonsoftJson {3.0.0-preview5-19227-01}
    • Microsoft.AspNetCore.SpaServices.Extensions {3.0.0-preview5-19227-01}
    • Microsoft.AspNetCore.Identity.EntityFrameworkCore {3.0.0-preview5-19227-01}
    • runtime.win-x64.Microsoft.NETCore.DotNetAppHost {3.0.0-preview4-27615-11}

    The problem I have, is that if I call that API part, I get the error:

    Information: Bearer was not authenticated. Failure message: No SecurityTokenValidator available for token:

    Any help would be much appreciated, since I can't find the error