ASP.NET Core 2.0 JWT Validation fails with `Authorization failed for user: (null)` error

45,582

Solution 1

The sequence of the add statements in the configure function is of importance. Make sure that

app.UseAuthentication();

comes before

app.UseMvc();

Might this have been the problem?

Solution 2

For Dotnetcore 3.1, I placed app.UseAuthentication() before app.UseAuthorization()

Solution 3

In your startup.cs ConfigureServices method if you add

services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options => ...

Explanation: When you use [Authorize] on a controller it binds to the first authorization system by default.

options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;

With this you are setting your default to JWT Bearer authentication.

additionally you can add

options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

this line is how to prevent getting 404 not found errors when using Identity with JWTs. If you are using identity the DefaultChallengeScheme will try to redirect you to a login page, which if non existent will result in getting a 404 not found rather than the wanted 401 unauthorized. by setting the DefaultChallengeScheme to JwtBearerDefaults.AuthenticationScheme on unauthorized it will no longer try to redirect you to a login page

If you are using Cookie Authentication with JWT authentication in the [Authorize] tag you can specify what authenticationScheme you want. for example

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

Solution 4

For anyone using .NET Core 3.1, this is how it works:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseCors("AllowOrigin");
    app.UseHttpsRedirection();
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

Solution 5

I added:

app.UseAuthentication();

In Startup.Configure() and that resolved this error for me.

Reference: Auth 2.0 Migration announcement

Share:
45,582
Alexey Strakh
Author by

Alexey Strakh

Updated on October 31, 2020

Comments

  • Alexey Strakh
    Alexey Strakh over 3 years

    I'm using ASP.NET Core 2.0 application (Web API) as a JWT issuer to generate a token consumable by a mobile app. Unfortunately, this token couldn't be validated by one controller while can be validated by another (using the same validation setting within the same asp.net core 2.0 app).

    So I have a token which is valid and could be decoded, has all the required claims and timestamps. But one endpoint accepts it, while another gives me 401 error and debug output:

    Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed for user: (null).

    [40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
          Authorization failed for user: (null).
    Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed for user: (null).
    [40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
          Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
    Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
    Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes ().
    [40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
          Executing ChallengeResult with authentication schemes ().
    [40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[12]
          AuthenticationScheme: Bearer was challenged.
    Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information: AuthenticationScheme: Bearer was challenged.
    [40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
          Executed action MyController.Get (WebApi) in 72.105ms
    Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action MyController.Get (WebApi) in 72.105ms
    Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 271.077ms 401 
    [40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
          Request finished in 271.077ms 401 
    

    My validation setup is below:

    var secretKey = Configuration["Authentication:OAuth:IssuerSigningKey"];
    var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));
    var tokenValidationParameters = new TokenValidationParameters
    {
       ValidateIssuerSigningKey = true,
       IssuerSigningKey = signingKey,
       ValidateIssuer = true,
       ValidIssuer = Configuration["Authentication:OAuth:Issuer"],
       ValidateAudience = true,
       ValidAudience = Configuration["Authentication:OAuth:Audience"],
       ValidateLifetime = true,
       ClockSkew = TimeSpan.Zero,
    };
    
    services.AddAuthentication(options =>
    {
       options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
       options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
       options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    }).AddJwtBearer(options =>
    {
        options.RequireHttpsMetadata = false;
        options.TokenValidationParameters = tokenValidationParameters;
    });
    

    These two endpoints are identical, just live in different controllers, both marked with the Authorize attribute.

    How is that possible?