Web api core returns 404 when adding Authorize attribute

Viewed 14843

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?

4 Answers

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

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(...);

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

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;
            });
Related