Search code examples
c#asp.net-corejwtasp.net-core-webapiasp.net-core-identity

Should return 401 but is returning 404


I have this ASP.NET Core 8 Web API project. I have an AuthenticationController and I have a protected endpoint. It returns an error http 404 when I try to access it with token and without it.

I suspect there is a problem with the authentication schemas:

[Authorize]
[ApiController]
[Route("[controller]/[action]")]
public class ApartmentController : ControllerBase
{
    private readonly IMediator _mediator;

    public ApartmentController(IMediator mediator)
    {
        _mediator = mediator;
    }

    [HttpPost]
    public async Task<IActionResult> Add([FromBody] AddApartmentDto dto)
    {
        var response = await _mediator.Send(new AddApartmentRequest(dto));

        if (response.StatusCode == (int)HttpStatusCode.OK)
            return Ok(new { id = response.Value });

        return StatusCode(response.StatusCode, new { problem = response.Message });
    }

    [HttpGet]
    [Route("/[controller]/{id:int}")]
    public async Task<IActionResult> Get(int id)
    {
        var response = await _mediator.Send(new GetApartmentRequest(id));

        if (response.StatusCode == (int)HttpStatusCode.OK)
            return Ok(response.Value);

        return StatusCode(response.StatusCode, new { problem = response.Message });
    }
    
    [HttpGet]
    [Route("/[controller]/schedule/{id:int}")]
    public async Task<IActionResult> GetSchedule(int id)
    {
        var response = await _mediator.Send(new GetScheduleRequest(id));

        if (response.StatusCode == (int)HttpStatusCode.OK)
            return Ok(response.Value);

        return StatusCode(response.StatusCode, new { problem = response.Message });
    }

    [HttpPost]
    [Route("/[controller]/schedule-viewing")]
    public async Task<IActionResult> ScheduleViewing([FromBody] ScheduleViewingDto dto)
    {
        var response = await _mediator.Send(new ScheduleViewingRequest(dto));

        if (response.StatusCode == (int)HttpStatusCode.OK)
            return Ok(new { message = response.Message });

        return StatusCode(response.StatusCode, new { problem = response.Message });
    }
}

This is my Program.cs file

...

builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidIssuer = config["JwtSettings:Issuer"],
        ValidAudience = config["JwtSettings:Audience"],
        IssuerSigningKey = new SymmetricSecurityKey(
            Encoding.UTF8.GetBytes(config["JwtSettings:Key"]!)),
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        RequireExpirationTime = true
    };
});
//.AddOAuth();

builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<IdentityContext>()
    .AddDefaultTokenProviders();

builder.Services.Configure<IdentityOptions>(options =>
{
    // Password settings
    options.Password.RequireDigit = true;
    options.Password.RequireLowercase = false;
    options.Password.RequireNonAlphanumeric = false;
    options.Password.RequireUppercase = false;
    options.Password.RequiredLength = 5;
    options.Password.RequiredUniqueChars = 1;
    
    // SignIn settings
    options.SignIn.RequireConfirmedEmail = true;

    // Lockout settings
    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(1);
    options.Lockout.MaxFailedAccessAttempts = 5;
    options.Lockout.AllowedForNewUsers = true;

    // User settings
    options.User.AllowedUserNameCharacters =
        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-.@_+";
    options.User.RequireUniqueEmail = true;
});

builder.Services.AddAuthorization();
    // .AddPolicy(nameof(Owner), policy => { policy.RequireRole(nameof(Owner)); })
    // .AddPolicy(nameof(Customer), policy => { policy.RequireRole(nameof(Customer)); })
    // .AddPolicy("Admin", policy => { policy.RequireRole("Admin"); });

...

builder.Services.AddInterfaceAdapters();
builder.Services.Configure<JwtSettings>(config.GetSection("JwtSettings"));

var app = builder.Build();

app.MapHealthChecks("/_health", new HealthCheckOptions
{
    ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

I tried to specify policies for the endpoint but it doesn't work.

Result in Postman


Solution

  • You need to change your Authorize attribute to [Authorize(AuthenticationSchemes = "Bearer")] since you are using JWT authentication scheme.

    What you encountering is happening because your API is not authorized and your redirect URL doesn't exist and hence a 404 not found is thrown. Also you should add the Identity before Authentication in your Program.cs