49

I am new to .net core, and I am trying to create web api core which implements jwt for authentication and authorization purposes.

Inside Startup class I configured it this way:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {

        services.AddDbContext<MandarinDBContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("MyConnection")));

        services.AddIdentity<User, Role>()
        .AddEntityFrameworkStores<MyDBContext>()
        .AddDefaultTokenProviders();

        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = false,
                        ValidateAudience = false,
                        ValidateLifetime = true,
                        ValidateIssuerSigningKey = true,
                        ValidIssuer = "yourdomain.com",
                        ValidAudience = "yourdomain.com",
                        IssuerSigningKey = new SymmetricSecurityKey(
                            Encoding.UTF8.GetBytes("My secret goes here"))
                    };

                    options.RequireHttpsMetadata = false;
                });

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

        // Add application services.
        services.AddTransient<IUserService, UserService>();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseHttpsRedirection();

        app.UseAuthentication();
        app.UseMvc();
    }
}

But when I try to call the following action:

    [Authorize]
    [HttpGet]
    [Route("api/Tokens")]
    public IActionResult TestAuthorization()
    {
        return Ok("You're Authorized");
    }

I get 404 not found. If I remove Authorize attribute it's working .

Could you please guide me to solve that issue?

3
  • Maybe this can shed some light: github.com/openiddict/openiddict-core/issues/498 Commented Aug 27, 2018 at 11:19
  • If you have cookie authentication on it might redirect you to a Not Found page, without it you just get a nice 401 - Authorization has been denied for this request. Commented Aug 27, 2019 at 7:00
  • [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] this is the solution Commented Mar 1, 2023 at 7:48

9 Answers 9

88

It happens when your API is not authorized and your redirect URL doesn't exist. When authentication fails, Web API will send a 401 code. Now if you are handling this code on the client side and doing a redirect for an authorization failure, then make sure that the redirected Url exists. Also, Do not add the [Authorize] attribute to the controller that handles Authentication methods (Login/Register). Your culprit looks to be the Authorize attribute. Since you are using JWT authentication scheme. Your authorize attribute should be following

    [Authorize(AuthenticationSchemes = "Bearer")]
    [HttpGet]
    [Route("api/Tokens")]
    public IActionResult TestAuthorization()
    {
        return Ok("You're Authorized");
    }

To make it default authentication scheme, Change AddIdentity to AddIdentityCore. here is a very good article.

Using JwtBearer Authentication in an API-only ASP.NET Core Project

Sign up to request clarification or add additional context in comments.

5 Comments

No I am not handling it on client side I am testing it using postMan
options.AccessDeniedPath = "/Identity/Account/AccessDenied"; Do you have something like this in your configure services code in startup.cs
No I don't have such a configuration and I am testing my endpoint using valid jwt token
Thanks alot it's working now. But I have one question can I configure that without need for providing AuthenticationSchemes parameter for every time I need to specify Authorize attribute?
oh bro thank u I was searching more than couple of days!
20

I had the same problem as you, I managed to solve by modifying ConfigureServices

from this

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(..)

to this

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

1 Comment

Thank you!! This fixed the specific 404 error code (not 401) issue I was seeing trying to use CookieAuthenticationDefaults.AuthenticationScheme and .AddCookie() in .NET 6 Core Minimal REST API.
7

In my case, I added configurations in the wrong order. Identity needs to be added before authentication.

Comments

4

When you are using JwtBearer tokens you can add this snippet to your ConfigureServices:

  services.AddControllers(opt => {
            var policy = new AuthorizationPolicyBuilder("Bearer").RequireAuthenticatedUser().Build();
            opt.Filters.Add(new AuthorizeFilter(policy));
        })

This will set bearer auth policy throughout the whole application and require authenticated users on every endpoint. Also you don't won't need to put [Authorize] on methods, and you can put [AllowAnonymous] on endpoints and controllers if you want them to be available to unauthenticated users.

Note: this works for .net core 3.1

1 Comment

While this did work, I ended up using the accepted answer since I could not get this to work when I needed to override and specify an authorize attribute with Roles.
1

it worked with me by using just the authorize attribute

[Authorize]
    public class WeatherForecastController : ControllerBase
    {...}

by this way in ConfigureServices

services.AddIdentity<ApplicationUser, ApplicationRole>(options => options.SignIn.RequireConfirmedAccount = true)
               .AddEntityFrameworkStores<OkazContext>();

            var key = Encoding.ASCII.GetBytes(Configuration["JwtConfig:Secret"]);

            var tokenValidationParams = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false,
                ValidateLifetime = true,
                RequireExpirationTime = false,
                ClockSkew = TimeSpan.Zero
            };

            services.AddSingleton(tokenValidationParams);

            services.AddAuthentication(options => {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(jwt => {
                jwt.SaveToken = true;
                jwt.TokenValidationParameters = tokenValidationParams;
            });

Comments

1
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

this is the solution

Comments

1

It may be cause the identity service registration comes after the authorization service registration in Program.cs.

It needs to be like that:

builder.Services.ConfigureIdentity();
builder.Services.ConfigureAuthorization(builder.Configuration);

Comments

0

As Code Name Jack mentioned, it was because of using Services.AddIdentity instead of Services.AddIdentityCore
Note that you need to add role entity manually using Services.AddRoles<TRole>()when using identity core

Comments

-1

I'm writing because I can hardly find the solution.

In my case the problem is that I'm using the Identity tool for user identity validation. Despite correctly generating the token and implementing the token validation correctly, whenever I used the [Authorize] tag I received 404 Not found.

Note that to mitigate the error there are 2 options, in my case.

  1. Change the [Authorize] tag to [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

Note that this option does not completely mitigate the error, but if you do not want to modify your program.cs it is your solution.

  1. Validate in Program.cs if you are using this line:

     builder.Services.AddIdentity<IdentityUser,IdentityRole().AddEntityFrameworkStores<Crediestado_GestionUsuarios>().AddDefaultTokenProviders();
    

You must always place it before your builder.Services.AddAuthentication();

In this order, the 404 Not Found will no longer appear.

2.1 Finally, if point 2 does not work, validate that your AddAuthentication declaration looks like this:

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

this way the 404 Not Found will no longer appear.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.