How to enable CORS in ASP.net Core WebAPI
Solution 1
Because you have a very simple CORS policy (Allow all requests from XXX domain), you don't need to make it so complicated. Try doing the following first (A very basic implementation of CORS).
If you haven't already, install the CORS nuget package.
Install-Package Microsoft.AspNetCore.Cors
In the ConfigureServices method of your startup.cs, add the CORS services.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(); // Make sure you call this previous to AddMvc
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
Then in your Configure method of your startup.cs, add the following :
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// Make sure you call this before calling app.UseMvc()
app.UseCors(
options => options.WithOrigins("http://example.com").AllowAnyMethod()
);
app.UseMvc();
}
Now give it a go. Policies are for when you want different policies for different actions (e.g. different hosts or different headers). For your simple example you really don't need it. Start with this simple example and tweak as you need to from there.
Further reading : http://dotnetcoretutorials.com/2017/01/03/enabling-cors-asp-net-core/
Solution 2
-
In ConfigureServices add
services.AddCors();
BEFORE services.AddMvc(); -
Add UseCors in Configure
app.UseCors(builder => builder .AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader()); app.UseMvc();
Main point is that add app.UseCors
, before app.UseMvc()
.
Make sure you declare the CORS functionality before MVC so the middleware fires before the MVC pipeline gets control and terminates the request.
After the above method works you can change it configure a specific ORIGIN to accept api calls and avoid leaving your API so open to anyone
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options => options.AddPolicy("ApiCorsPolicy", builder =>
{
builder.WithOrigins("http://localhost:4200").AllowAnyMethod().AllowAnyHeader();
}));
services.AddMvc();
}
In the configure method tell CORS to use the policy you just created:
app.UseCors("ApiCorsPolicy");
app.UseMvc();
I just found this compact article on the subject - https://dzone.com/articles/cors-in-net-core-net-core-security-part-vi
Solution 3
I created my own middleware class that worked for me, i think there is something wrong with .net core middleware class
public class CorsMiddleware
{
private readonly RequestDelegate _next;
public CorsMiddleware(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext httpContext)
{
httpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
httpContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
httpContext.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
httpContext.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");
return _next(httpContext);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class CorsMiddlewareExtensions
{
public static IApplicationBuilder UseCorsMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CorsMiddleware>();
}
}
and used it this way in the startup.cs
app.UseCorsMiddleware();
Solution 4
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseCors(builder => builder
.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed((host) => true)
.AllowCredentials()
);
}
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
}
Solution 5
I was struggling with this for DAYS.
I finally got it to work by moving app.UseCors(CORS_POLICY);
to the TOP of Configure()
.
https://weblog.west-wind.com/posts/2016/sep/26/aspnet-core-and-cors-gotchas
Make sure you declare the CORS functionality before > MVC as the headers have to be applied before MVC completes the request.
<= Even though my app didn't call
UseMVC()
, movingUseCors()
to the top fixed the problem
Also:
-
Microsoft.AspNetCore.Cors
used to be a required NuGet package in .Net Core 2 and lower; it's now automatically a part of Microsoft.AspNetCore in .Net Core 3 and higher. -
builder.AllowAnyOrigin()
and.AllowCredentials()
CORS options are now mutually exclusive in .Net Core 3 and higher - CORS policy seems to require Angular call the server with
https
. An http URL seemed to give a CORS error regardless of the .Net Core server's CORS configuration. For example,http://localhost:52774/api/Contacts
would give a CORS error; simply changing the URL tohttps://localhost:44333/api/Contacts
worked.
Additional note:
In my case, CORS wouldn't work until I moved
app.UseCors()
aboveapp.UseEndpoints(endpoints => endpoints.MapControllers())
.
Related videos on Youtube
killerrin
Updated on July 16, 2022Comments
-
killerrin almost 2 years
What I am trying to do
I have a backend ASP.Net Core Web API hosted on an Azure Free Plan (Source Code: https://github.com/killerrin/Portfolio-Backend).
I also have a Client Website which I want to make consume that API. The Client Application will not be hosted on Azure, but rather will be hosted on Github Pages or on another Web Hosting Service that I have access to. Because of this the domain names won't line up.
Looking into this, I need to enable CORS on the Web API side, however I have tried just about everything for several hours now and it is refusing to work.
How I have the Client Setup Its just a simple client written in React.js. I'm calling the APIs through AJAX in Jquery. The React site works so I know its not that. The Jquery API call works as I confirmed in Attempt 1. Here is how I make the calls
var apiUrl = "http://andrewgodfroyportfolioapi.azurewebsites.net/api/Authentication"; //alert(username + "|" + password + "|" + apiUrl); $.ajax({ url: apiUrl, type: "POST", data: { username: username, password: password }, contentType: "application/json; charset=utf-8", dataType: "json", success: function (response) { var authenticatedUser = JSON.parse(response); //alert("Data Loaded: " + authenticatedUser); if (onComplete != null) { onComplete(authenticatedUser); } }, error: function (xhr, status, error) { //alert(xhr.responseText); if (onComplete != null) { onComplete(xhr.responseText); } } });
What I have tried
Attempt 1 - The 'proper' way
https://docs.microsoft.com/en-us/aspnet/core/security/cors
I have followed this tutorial on the Microsoft Website to a T, trying all 3 options of enabling it Globally in the Startup.cs, Setting it up on every controller and Trying it on every Action.
Following this method, the Cross Domain works, but only on a single Action on a single controller (POST to the AccountController). For everything else, the
Microsoft.AspNetCore.Cors
middleware refuses to set the headers.I installed
Microsoft.AspNetCore.Cors
through NUGET and the version is1.1.2
Here is how I have it setup in Startup.cs
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // Add Cors services.AddCors(o => o.AddPolicy("MyPolicy", builder => { builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); })); // Add framework services. services.AddMvc(); services.Configure<MvcOptions>(options => { options.Filters.Add(new CorsAuthorizationFilterFactory("MyPolicy")); }); ... ... ... } // This method gets called by the runtime. Use this method to configure //the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); // Enable Cors app.UseCors("MyPolicy"); //app.UseMvcWithDefaultRoute(); app.UseMvc(); ... ... ... }
As you can see, I am doing everything as told. I add Cors before MVC both times, and when that didn't work I attempted putting
[EnableCors("MyPolicy")]
on every controller as so[Route("api/[controller]")] [EnableCors("MyPolicy")] public class AdminController : Controller
Attempt 2 - Brute Forcing it
https://andrewlock.net/adding-default-security-headers-in-asp-net-core/
After several hours of trying on the previous attempt, I figured I would try to bruteforce it by trying to set the headers manually, forcing them to run on every response. I did this following this tutorial on how to manually add headers to every response.
These are the headers I added
.AddCustomHeader("Access-Control-Allow-Origin", "*") .AddCustomHeader("Access-Control-Allow-Methods", "*") .AddCustomHeader("Access-Control-Allow-Headers", "*") .AddCustomHeader("Access-Control-Max-Age", "86400")
These are other headers I tried which failed
.AddCustomHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE") .AddCustomHeader("Access-Control-Allow-Headers", "content-type, accept, X-PINGOTHER") .AddCustomHeader("Access-Control-Allow-Headers", "X-PINGOTHER, Host, User-Agent, Accept, Accept: application/json, application/json, Accept-Language, Accept-Encoding, Access-Control-Request-Method, Access-Control-Request-Headers, Origin, Connection, Content-Type, Content-Type: application/json, Authorization, Connection, Origin, Referer")
With this method, the Cross Site headers are being properly applied and they show up in my developer console and in Postman. The problem however is that while it passes the
Access-Control-Allow-Origin
check, the webbrowser throws a hissy fit on (I believe)Access-Control-Allow-Headers
stating415 (Unsupported Media Type)
So the brute force method doesn't work either
Finally
Has anyone gotten this to work and could lend a hand, or just be able to point me in the right direction?
EDIT
So to get the API calls to go through, I had to stop using JQuery and switch to a Pure Javascript
XMLHttpRequest
format.Attempt 1
I managed to get the
Microsoft.AspNetCore.Cors
to work by following MindingData's answer, except within theConfigure
Method putting theapp.UseCors
beforeapp.UseMvc
.In addition, when mixed with the Javascript API Solution
options.AllowAnyOrigin()
for wildcard support began to work as well.Attempt 2
So I have managed to get Attempt 2 (brute forcing it) to work... with the only exception that the Wildcard for
Access-Control-Allow-Origin
doesn't work and as such I have to manually set the domains that have access to it.Its obviously not ideal since I just want this WebAPI to be wide opened to everyone, but it atleast works for me on a separate site, which means it's a start
app.UseSecurityHeadersMiddleware(new SecurityHeadersBuilder() .AddDefaultSecurePolicy() .AddCustomHeader("Access-Control-Allow-Origin", "http://localhost:3000") .AddCustomHeader("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PUT, PATCH, DELETE") .AddCustomHeader("Access-Control-Allow-Headers", "X-PINGOTHER, Content-Type, Authorization"));
-
Technetium almost 7 yearsFor your
415 (Unsupported Media Type)
issue, set aContent-Type
request header toapplication/json
. -
user1007074 over 5 yearsThanks for spending the time to write a such a descriptive question.
-
tala9999 over 5 yearsIf you are testing using Postman, make sure you set Origin to * or something for the request header, then Attempt #1 should work. Without this header, Access-Control-Allow-Origin will not be returned in the response header.
-
Kirk Hawley over 3 yearsIt was the comment below about XMLHttpRequest that did it for me, thanks!
-
Gilbert over 2 yearsI am struggling with the same thing. Since yesterday. I am also trying to brute force it using my custom middleware. Its such a headache
-
Igor Mironenko about 2 yearsAlmost glad to know others are spending hours on this - I can't get anything to work, not even a little bit, about to try some version of your brute force
-
-
killerrin almost 7 yearsXMLHttpRequest cannot load andrewgodfroyportfolioapi.azurewebsites.net/api/Authentication. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'localhost:3000' is therefore not allowed access. The response had HTTP status code 415.
-
killerrin almost 7 yearsUnfortunately that didn't work. I added the code as you/the tutorial said (in the order its listed in too), with example.com replaced with localhost:3000 and I get an error
-
killerrin almost 7 yearsThanks for your help. Definitely utilized a portion of the answer to figure out the solution in the end after combining everyones answers
-
killerrin almost 7 yearsSo with some tweaking around I got this solution to work. It looks like the problem was in using Jquery AJAX for api calls as once I switched to a pure Javascript solution using XMLHttpRequest it ended up working. I'll accept this answer and do a writeup in the main post
-
killerrin almost 7 yearsThanks for your help. Tried a new solution and played with json being sent out and it worked after I stringified it and got it to work
-
Tseng almost 7 yearsThis is unlikely going to work, when you register
app.UseCors
AFTER `` app.UseMvc()`. Middlewares are executed in the order they are registered -
MrClan over 6 yearsusing app.UseCors before app.UseMvc, in Configure method seems to work. For some reason, the sequence does seem to matter.
-
MindingData over 6 yearsSorry yes. I had it wrong in original answer, changed it now. They are executed in order AND middleware can short circuit the process (So it doesn't go any further)
-
Artur Poniedziałek over 6 yearsVery elegant way of running Access-Control-Allow-Origin.
-
Rivon over 6 yearsAgree with Towhid that AllowAnyHeader() is needed. It let server receives OPTIONS request if HEADER's request is missing something.
-
Andrii M4n0w4R over 6 yearsFor me, the biggest problem of CORS in 2.0 is that it doesn't tell what is wrong, just silently failing to set CORS headers. Note: remember to add all your required headers to policy or it will fail (i had content-type). Also weird thing for me that CORS middleware doesn't brake request processing, just informing in logs that origin is not allowed and.. Passes request further (middleware order was correct).
-
hubert17 over 6 yearsThis works for me. codeproject.com/Articles/1150023/…
-
Indy-Jones over 6 yearsThis should really get more upvotes as a good "starting" point. In my experience over 25 years of coding it's always nice to know how to open up the floodgates to make sure it does in fact "work" and then close/secure things as needed.
-
Michael Brown about 6 yearsI had to enable
options.DisableHttpsRequirement();
in order for any of this to work. It seems with https cors settings were not applying. -
Felix K. almost 6 yearsJust to mention this, in contrast to
Configure()
the order is not really important here withinConfigureServices()
-
Richard almost 6 yearsI used the link in the Further Reader and those steps resolved this error. I wasn't sure where these changes should be placed (I thought the API). The Link confirmed that they should be placed in the API. Thanks for the help. I was totally spinning my wheels with this error.
-
Joe almost 6 yearsThis works on WebAPI and MVC and has no dependencies, Thank you!
-
Michal Frystacky almost 6 yearsThis works with Asp.Net Core 2.1 and with more importantly with localhost
-
Jordan Ryder almost 6 yearsI was skeptical about this also, but it worked for me. I tried basically every other method to accomplish this that I could find on the internet, but no matter what the server would not respond with the access headers. This worked great. I'm running aspnetcore 2.1.
-
Junior Mayhé over 5 yearsJust for the record, sometimes Cors is not working when a client app is calling the wrong webserver URL with POST. If URL is wrong, OPTIONS will show 204 but POST may fire 404 or 500.
-
Albert221 over 5 yearsI recommend adding middleware that way:
app.Use<CorsMiddleware>();
-
Hayha over 5 yearsYou can replace those 2 ligne : context.Response.StatusCode = (int)HttpStatusCode.OK; await context.Response.WriteAsync(string.Empty); with a simple : return;
-
Adam over 5 yearsTo expand on your expansion of @user8266077's answer: Beware that if the request for some other reason fails, this middleware will throw an exception and the headers will not be set. Meaning that in frontend, it will still look like a CORS issue even though it's something totally different. I bypassed this by catching any exceptions in
await _next(context)
and setting the status code and response manually if this happens. I also had to add "authorization" to Access-Control-Allow-Headers for the preflight request to work when making requests from react that requires authorization. -
takaz over 5 yearsThe .AllowAnyHeader() did it for me, I had issues with the preflight response.
-
Moussa Khalil about 5 yearsDidn't work for me until both sides were http (angular ng serve was http, core backend was https).
-
Nick De Beer almost 5 yearsFYI - The CORS specification also states that setting origins to "*" (all origins) is invalid if the Access-Control-Allow-Credentials header is present. Meaning you cannot use
AllowCredentials()
withAllowAnyOrigin()
like above. To useAllowCredentials()
you need to setWithOrigins()
. docs.microsoft.com/en-us/aspnet/core/security/… -
Andrei Prigorshnev almost 5 yearsYou should return cors headers only if client send header "Origin" in request. In original CospMiddleware it looks like this:
if (!context.Request.Headers.ContainsKey(CorsConstants.Origin)) return this._next(context);
-
Andrei Prigorshnev almost 5 yearsMaybe "something wrong with .net core middleware class" because you just don't add header "Origin" when testing it with curl or something like this. Browsers add this header automatically when you make a request in js code.
-
Andrei Prigorshnev almost 5 yearsSee more details here developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Simple_requests –
-
Paul Kertscher almost 5 yearsThank you very much. I nearly went nuts, asking myself why the
Access-Control-Allow-Origin
header was not issued by the server. Actually I sent requests via Postman w/o theOrigin
header. This saved my day! (Or at least my forenoon ;) ) -
HaRoLD over 4 yearsThis did it for me, I originally setup my project for Windows Authentication but then had to change it to anonymous, I had CORS correctly configured but this setting in launchSettings.json was the culprit, thank you for posting this!.
-
Levi Fuller over 4 yearsHave to update to
builder.WithOrigins("http://localhost:4200").AllowAnyCredentials()...
As @NickDeBeer mentioned, it won't work in 2.2 without explicitly specifying the allowed origins. -
FoggyDay over 4 yearsNOTE: you shouldn't use Microsoft.AspNet.Cors in an ASP.Net Cor application. If you're on .Net Core 3.0 or higher, you don't need to import any NuGet package at all for CORS. If you're on .Net Core 2.3 or lower, then you need the appropriate version of Microsoft.AspNet.Cors from NuGet.
-
FoggyDay over 4 yearsThis is probably a bad idea: you shouldn't mix middleware (
app.UseCors()
) with[EnableCors()]
in the same application. You should use one or the other - but not both: docs.microsoft.com/en-us/aspnet/core/security/…:Use the [EnableCors] attribute or middleware, not both in the same app.
-
Canada Wan over 4 yearsThis one should be the answer if you are using Net Core 3. Thanks for saving my life!
-
JensB over 4 years.SetIsOriginAllowed((host) => true) solved it for me.
-
JensB over 4 years.SetIsOriginAllowed((host) => true) solved it for me. in Configure, app.UseCores() solved it for me, nothing else worked.
-
Mark Schultheiss about 4 years"With endpoint routing, the CORS middleware must be configured to execute between the calls to UseRouting and UseEndpoints. Incorrect configuration will cause the middleware to stop functioning correctly." here docs.microsoft.com/en-us/aspnet/core/security/…
-
Mark Schultheiss about 4 years"With endpoint routing, the CORS middleware must be configured to execute between the calls to UseRouting and UseEndpoints. Incorrect configuration will cause the middleware to stop functioning correctly." here docs.microsoft.com/en-us/aspnet/core/security/…
-
roberto tomás about 4 yearswow, so I fully expected any of the other answers to work before this little one with only 3 votes. but I meticulously tried each one, ... on a whim I went for yours and, it worked. thank you
-
Giox about 4 years@MindingData Why I need to add UseMVC() in a pure WebAPI project? Is it necessary to load all the MVC stuff to make the CORS works??
-
sean about 4 yearsThis did not work for me. I had to use the lambda AddPolicy in the services.AddCors with the allow options giving it a name. Then I just used app.UseCors("myCorsPolicy"); in configure. And then used the [EnableCors("myCorsPolicy")] attribute for the web methods I expect cors on.
-
Brian almost 4 yearsIf you do the above in core 3.1 your get the following error message "The CORS protocol does not allow specifying a wildcard (any) origin and credentials at the same time. Configure the CORS policy by listing individual origins if credentials needs to be supported.'"
-
jasmintmp almost 4 yearsIt didn't work for me as well, I'm hosting my front on IIS localhost:80 an backend API on IIS localhost:86 Chrome receiving error: "..from origin 'localhost:86' has been blocked by CORS policy: Request .." If I equal the ports it goes well. Tricky stuff is even if you remove you backend API Chrome is still trying to preflight OPTIONS to backend and fails with the same CORS exception instead of 404.
-
JustinHui almost 4 yearsThis is the one that worked for me on .NET Core 3.1 to allow pretty much anything.
-
Brandonm almost 4 yearsI ran into something similar this when I upgraded from dotnet core 2.2 to 3.1. Had to move app.UseCors() above app.UseRouting(). This answer pointed me in the right direction.
-
Saurabh Rana over 3 yearsThanks. This is the only solution that worked for me.The order of [code]services.AddCors();[/code] also matters.
-
smithygreg over 3 yearsThis also was the only one that worked for me. SignalR Asp.Net Core 3.1
-
PT2550 about 3 yearsYour reference to using https URL instead of http worked for me. I've been stuck for days trying to figure this out. Thanks!
-
FoggyDay about 3 yearsGlad it helped :)
-
Dan Chase almost 3 years@Brian something that really confuses me, is I keep seeing examples that look like code-paste's that claim to work, and I know they don't, because this is the reason I'm searching. But somehow, it must have worked for them. shrug.
-
KylianMbappe over 2 yearsThank you! Only solution that worked for me!
-
Rich Freeman over 2 yearsOh gosh - thank you (.net 5/6) - spent literally days banging my head against this one. It appears Azure implements its own CORS functionality on APIs and Websites in an App Service. This is not mentioned anywhere in any documentation I've found whilst googling. If you use Azure give this a try!
-
crazyTech about 2 yearsThanks.According to the technical docs, it says SetIsOriginAllowed "Sets the specified isOriginAllowed for the underlying policy" Could someone please elaborate in a more details as to what said method does? Thx