What to do if you get the following error in the browser when calling a CORS protected .NET Core API endpoint:
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access. The response had HTTP status code 405.
CHECK 1: ALLOW METHOD “OPTIONS”:
A preflight request is a request that the browser issues to check if the CORS settings are implemented correct.
So if your endpoint is a POST, PUT or DELETE endpoint, and the browser sends a request with type “application/json“, the browser sends 2 requests, first the “OPTIONS” request, followed by a POST, PUT or DELETE.
In the CORS settings of your application, you must therefore also allow OPTIONS:
app.UseCors(builder =>
{
builder
.WithOrigins("http://localhost:4200", "https://localhost:4200")
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyHeader()
.AllowCredentials()
.WithMethods("GET", "PUT", "POST", "DELETE", "OPTIONS")
.SetPreflightMaxAge(TimeSpan.FromSeconds(3600));
}
);
CHECK 2: CORS IS DEFINED TWICE IN YOUR CODE:
Check that you have defined CORS twice.
First add CORS to the WebApplicationBuilder Services:
var builder = WebApplication.CreateBuilder();
...
...
builder.Services.AddCors();
Then when defining the app:
var app = builder.Build();
app.UseCors(builder =>
{
builder
.WithOrigins("http://localhost:4200", "https://localhost:4200")
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyHeader()
.AllowCredentials()
.WithMethods("GET", "PUT", "POST", "DELETE", "OPTIONS")
.SetPreflightMaxAge(TimeSpan.FromSeconds(3600));
}
);
CHECK 3: CHECK THE SEQUENCE OF CALLS:
You must define CORS before you map controllers, define routes etc.
var app = builder.Build();
// The first thing in the chain of calls is to define the CORS
app.UseCors(builder =>
{
builder
.WithOrigins("http://localhost:4200", "https://localhost:4200")
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyHeader()
.AllowCredentials()
.WithMethods("GET", "PUT", "POST", "DELETE", "OPTIONS")
.SetPreflightMaxAge(TimeSpan.FromSeconds(3600));
}
);
...
...
// After that, I can do mapping, routing, redirection etc...
app.MapControllers();
app.UseRouting();
app.UseHttpsRedirection();
if (app.Environment.IsProduction())
{
app.UseTokenAuthentication();
}
app.Run();
CHECK 4: YOUR LOAD BALANCER MUST ALLOW “OPTIONS” AS WELL
Do you have a load balancer in front of your API? Make sure that the load balancer allows OPTIONS methods as well.
You are now a Cross-Origin Resource Sharing expert. Happy coding.
MORE TO READ:
- In ASP.NET, Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header from StackOverflow
- Preflight request documentation from Mozilla
- Enable Cross-Origin Requests (CORS) in ASP.NET Core from Microsoft
- Test CORS with endpoint routing and [HttpOptions] from Microsoft
- 3 Ways to Fix the CORS Error — and How the Access-Control-Allow-Origin Header Works by David Katz
- How to add default security headers in ASP.NET Core using custom middleware by Andrew Lock
- ASP.NET 5/Core/vNext CORS not working even if allowing pretty much everything from StackOverflow
- .NET Core API and CORS – allow POST from Javascript using Microsoft.AspNetCore.Cors by briancaos
- Azure API Management configure CORS in the policy by briancaos
Pingback: .NET Core Caching in your API using AddResponseCaching and ResponseCache attribute | Brian Pedersen's Sitecore and .NET Blog