Search code examples
asp.net-coreswaggerasp.net-core-webapi

Getting 405 error instead of 401 while implementing authentication in ASP.NET Core Web API


When I call the controller GetWeatherByQuery without authentication, I get a http 405 error instead of the expected 401.

But if I call after doing the authentication it works perfectly.

Why it is not returning Unauthorized (without authentication) even if [Authorize] attribute is used?

[ApiController]
[Authorize]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private readonly ILogger<WeatherForecastController> _logger;
    private readonly IWeatherForecast _weatherForecast;

    public WeatherForecastController(ILogger<WeatherForecastController> logger, IConfiguration configuration, IWeatherForecast weatherForecast)
    {
        _logger = logger;
        _weatherForecast = weatherForecast;
    }

    [HttpGet]
    [Route("GetWeatherByQuery/{query}")]
    [ProducesResponseType(StatusCodes.Status200OK,Type=typeof(WeatherForecastModel))]
    public async Task<ActionResult> Get(string query)
    {
        var result = await _weatherForecast.GetWeatherByCityAsync(query);
        return Ok(result);
    }
}

I have added following lines at appropriate places in Startup.cs:

services.AddAuthentication(
    CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.Cookie.Name = "Cookie";
        options.LoginPath = "/Account/Login";
    });

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

Solution

  • When you configure your options.LoginPath with Cookie authentication, it uses this path as the redirection target when the challenge fails. If you don't want to be redirected and just get the status code, you should overwrite this behavior:

    .AddCookie(options =>
    {
        options.Cookie.Name = "Cookie";
        options.LoginPath = "/Account/Login";
        options.Events.OnRedirectToLogin = context =>
        {
            context.Response.StatusCode = StatusCodes.Status401Unauthorized;
            return Task.CompletedTask;
        };
        options.Events.OnRedirectToAccessDenied = context =>
        {
            context.Response.StatusCode = StatusCodes.Status403Forbidden;
            return Task.CompletedTask;
        };
    });