'Unexplained 401 response from PUT method on .Net Core 3.1

I have a very intriguing problem. I have a .Net Core 3.1 Rest Web API. Background info:

  1. I've configured auth properly in line with our other microservices.
  2. The POST is authenticating properly and returns 200 OK
  3. The PUT operation returns 401 UnAuthorized
  4. I do nothing in terms of auth on a route-by-route basis

Controller snippet:

[Route("flights")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class FlightsController : BaseController
{
    private readonly ILogger<FlightsController> _logger;
    private readonly IStringLocalizer _stringLocalizer;
    private readonly IWebHostEnvironment _environment;
    public FlightsController(ILogger<FlightsController> logger, 
                             IStringLocalizer stringLocalizer, 
                             IWebHostEnvironment environment)
    {
        _logger = logger;     
        _stringLocalizer = stringLocalizer;
        _environment = environment;
    }

    [HttpPost("OrderFlight")]
    public async Task<IActionResult> OrderFlight([FromBody] OrderFlightBindingModel model)
    {
        return Ok(model);
    }

    [HttpPut("OrderFlight")]
    public async Task<IActionResult> ValidateOtp([FromBody] CompleteOrderBindingModel model)
    {
        return Ok(model);
    }
}

Startup Services Config snippet:

//Configure Services
services.AddAuthentication(options =>
{
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.Authority = _config["JWT:Authority"];
    options.Audience = _config["JWT:Audience"];
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuerSigningKey = true,
        ValidateIssuer = true,
        ValidateLifetime = true,
        ValidateAudience = true
    };
});
services.AddAuthorization();

startup Configure snippet:

//Configure
app.UseAuthentication();
app.UseAuthorization();

Any ideas are welcome. I'm pretty familiar with .Net Core API's, so assume I've done the relevant appsettings stuff right, and that I haven't missed something because there are 12 or so endpoints in total and only the one PUT operation returns 401 even though auth is applied across the entire controller, and not on a per-method basis. I am debugging on Localhost using VS Professional and Kestrel.



Solution 1:[1]

You don't need to use Put since some browsers don't support it. Fix the action headers:

   [Route("OrderFlight")]
    public async Task<IActionResult> OrderFlight([FromBody] OrderFlightBindingModel model)
    {
        return Ok(model);
    }

    [Route("ValidateOtp")]
    public async Task<IActionResult> ValidateOtp([FromBody] CompleteOrderBindingModel model)
    {
        return Ok(model);
    }
and use OrderFlight or ValidateOtp in your url.

Solution 2:[2]

Well I still can't explain the behaviour, but at least I've learned one or two things:

sending the PUT request via FlurlHttp returns 401. Sending the exact same request via PostMan works as expected. I triple checked and the headers, URL, Method, and body are all identical. So

So, it's a bug I'll have to raise with the Flurl developers. Since the PUT request works from PostMan, I am confident it will also work just like every other service's PUT OTP request that shares the same setup and has been working in our UAT and Production environments. So I will create a POST endpoint for the explicit purpose of testing it (which is technically a bad thing, but in the end I care more about working software than about DRY principles).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Serge
Solution 2 Captain Kenpachi