Web api core returns 404 when adding Authorize attribute

12,583

Solution 1

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

Solution 2

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

Solution 3

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(...);
Share:
12,583

Related videos on Youtube

Simple Code
Author by

Simple Code

Primarily interested in Microservices Domain-Driven Design(DDD) Software Design, Patterns, and Practices Elasticsearch

Updated on January 30, 2022

Comments

  • Simple Code
    Simple Code over 2 years

    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?

    • Peter B
      Peter B almost 6 years
      Maybe this can shed some light: github.com/openiddict/openiddict-core/issues/498
    • Nick Kovalsky
      Nick Kovalsky almost 5 years
      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.
  • Simple Code
    Simple Code almost 6 years
    No I am not handling it on client side I am testing it using postMan
  • Code Name Jack
    Code Name Jack almost 6 years
    options.AccessDeniedPath = "/Identity/Account/AccessDenied"; Do you have something like this in your configure services code in startup.cs
  • Simple Code
    Simple Code almost 6 years
    No I don't have such a configuration and I am testing my endpoint using valid jwt token
  • Simple Code
    Simple Code almost 6 years
    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?
  • Gabe
    Gabe almost 3 years
    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.