322

What I am trying to do

I have a backend ASP.Net Core Web API hosted on an Azure Free Plan (Add default security headers in .Net Core).

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://learn.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 is 1.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 stating 415 (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 the Configure Method putting the app.UseCors before app.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"));
Osama Rizwan
  • 615
  • 1
  • 7
  • 19
killerrin
  • 3,367
  • 3
  • 13
  • 9
  • 3
    For your `415 (Unsupported Media Type)` issue, set a `Content-Type` request header to `application/json`. – Technetium Jun 06 '17 at 00:54
  • 14
    Thanks for spending the time to write a such a descriptive question. – user1007074 Aug 11 '18 at 21:02
  • 2
    If 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. – tala9999 Jan 25 '19 at 16:59
  • It was the comment below about XMLHttpRequest that did it for me, thanks! – Kirk Hawley Dec 29 '20 at 21:20
  • I am struggling with the same thing. Since yesterday. I am also trying to brute force it using my custom middleware. Its such a headache – Gilbert Aug 05 '21 at 16:10
  • Almost 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 – PandaWood Mar 30 '22 at 08:46

37 Answers37

332

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/

Mauricio Gracia Gutierrez
  • 10,288
  • 6
  • 68
  • 99
MindingData
  • 11,924
  • 6
  • 49
  • 68
  • 12
    XMLHttpRequest cannot load http://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 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 415. – killerrin Jun 06 '17 at 03:53
  • Unfortunately that didn't work. I added the code as you/the tutorial said (in the order its listed in too), with http://example.com replaced with http://localhost:3000 and I get an error – killerrin Jun 06 '17 at 03:56
  • 1
    So 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 Jun 08 '17 at 01:29
  • 10
    This is unlikely going to work, when you register `app.UseCors` **AFTER** `` app.UseMvc()`. Middlewares are executed in the order they are registered – Tseng Jun 08 '17 at 05:57
  • 31
    using app.UseCors before app.UseMvc, in Configure method seems to work. For some reason, the sequence does seem to matter. – MrClan Aug 16 '17 at 05:16
  • Sorry 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) – MindingData Aug 16 '17 at 06:05
  • 2
    For 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). – Andrii M4n0w4R Nov 13 '17 at 16:10
  • 4
    I had to enable `options.DisableHttpsRequirement();` in order for any of this to work. It seems with https cors settings were not applying. – Michael Brown Mar 22 '18 at 06:30
  • Didn't work for me until both sides were http (angular ng serve was http, core backend was https). – Moussa Khalil Feb 17 '19 at 11:27
  • 2
    .SetIsOriginAllowed((host) => true) solved it for me. in Configure, app.UseCores() solved it for me, nothing else worked. – JensB Jan 18 '20 at 09:06
  • 5
    @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?? – Giox Mar 31 '20 at 19:40
  • This 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. – sean Apr 22 '20 at 16:29
  • It 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 'http://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. – jasmin May 16 '20 at 00:21
293
  • 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

Mohammed Osman
  • 3,688
  • 2
  • 27
  • 25
Ji Ra
  • 3,187
  • 1
  • 12
  • 17
  • 1
    This works for me. https://www.codeproject.com/Articles/1150023/Enable-Cross-origin-Resource-Sharing-CORS-in-ASP-N – hubert17 Dec 16 '17 at 19:38
  • 32
    This 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. – Indy-Jones Dec 21 '17 at 20:24
  • 4
    Just to mention this, in contrast to `Configure()` the order is not really important here within `ConfigureServices()` – Felix K. May 01 '18 at 19:32
  • 1
    I 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. – Richard May 14 '18 at 12:37
  • This works with Asp.Net Core 2.1 and with more importantly with localhost – Michal Frystacky Jul 11 '18 at 01:31
  • Just 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. – Junior Mayhé Aug 04 '18 at 22:52
  • 2
    FYI - 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()` with `AllowAnyOrigin()` like above. To use `AllowCredentials()` you need to set `WithOrigins()`. https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.2 – Nick De Beer Jun 21 '19 at 15:39
  • Have 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. – Levi Fuller Oct 23 '19 at 04:30
  • If 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.'" – Brian Apr 30 '20 at 21:43
  • @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. – Dan Chase Jun 23 '21 at 03:47
46
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {      
       app.UseCors(builder => builder
                .AllowAnyHeader()
                .AllowAnyMethod()
                .SetIsOriginAllowed((host) => true)
                .AllowCredentials()
            );
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors();
    }
Mo D Genesis
  • 5,187
  • 1
  • 21
  • 32
  • 2
    .SetIsOriginAllowed((host) => true) solved it for me. – JensB Jan 18 '20 at 09:05
  • wow, 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 – roberto tomás Feb 13 '20 at 22:41
  • This is the one that worked for me on .NET Core 3.1 to allow pretty much anything. – JustinHui Jul 08 '20 at 10:49
  • Thanks. This is the only solution that worked for me.The order of [code]services.AddCors();[/code] also matters. – Saurabh Rana Aug 17 '20 at 15:03
  • This also was the only one that worked for me. SignalR Asp.Net Core 3.1 – smithygreg Aug 25 '20 at 18:23
  • Thanks.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 – crazyTech Apr 05 '22 at 19:14
41

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();
user8266077
  • 437
  • 4
  • 2
  • Very elegant way of running Access-Control-Allow-Origin. – Artur Poniedziałek Aug 25 '17 at 12:52
  • This works on WebAPI and MVC and has no dependencies, Thank you! – Joe May 24 '18 at 02:14
  • 3
    I 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. – Jordan Ryder Jul 19 '18 at 13:43
  • 1
    You 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 Jun 27 '19 at 12:43
  • 2
    Maybe "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 Jun 27 '19 at 12:43
  • See more details here developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Simple_requests – – Andrei Prigorshnev Jun 27 '19 at 12:43
25

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(), moving UseCors() 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 to https://localhost:44333/api/Contacts worked.

Additional note:

In my case, CORS wouldn't work until I moved app.UseCors() above app.UseEndpoints(endpoints => endpoints.MapControllers()).

FoggyDay
  • 11,962
  • 4
  • 34
  • 48
  • 6
    This one should be the answer if you are using Net Core 3. Thanks for saving my life! – Canada Wan Jan 16 '20 at 15:04
  • 4
    "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 https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.1#cpo – Mark Schultheiss Jan 31 '20 at 22:46
  • 1
    "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 https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.1#cpo – Mark Schultheiss Jan 31 '20 at 22:46
  • 1
    Your reference to using https URL instead of http worked for me. I've been stuck for days trying to figure this out. Thanks! – PT2550 Mar 31 '21 at 20:52
  • Glad it helped :) – FoggyDay Apr 01 '21 at 01:19
22

In my case only get request works well according to MindingData's answer. For other types of request you need to write:

app.UseCors(corsPolicyBuilder =>
   corsPolicyBuilder.WithOrigins("http://localhost:3000")
  .AllowAnyMethod()
  .AllowAnyHeader()
);

Don't forget to add .AllowAnyHeader()

Towhid
  • 1,920
  • 3
  • 36
  • 57
  • 1
    Agree with Towhid that AllowAnyHeader() is needed. It let server receives OPTIONS request if HEADER's request is missing something. – Rivon Oct 18 '17 at 04:29
  • The .AllowAnyHeader() did it for me, I had issues with the preflight response. – takaz Jan 08 '19 at 03:55
17

For .NET CORE 3.1

In my case, I was using https redirection just before adding cors middleware and able to fix the issue by changing order of them

What i mean is:

change this:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {

      ...
        
        app.UseHttpsRedirection();  

        app.UseCors(x => x
            .AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader());

      ...

     }

to this:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {

      ...
        
        app.UseCors(x => x
            .AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader());

        app.UseHttpsRedirection(); 

      ...

     }

By the way, allowing requests from any origins and methods may not be a good idea for production stage, you should write your own cors policies at production.

okan
  • 790
  • 10
  • 11
14

For .Net Core 6

var builder = WebApplication.CreateBuilder(args);
var apiCorsPolicy = "ApiCorsPolicy";

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: apiCorsPolicy,
                      builder =>
                      {
                          builder.WithOrigins("http://localhost:4200", "https://localhost:4200")
                            .AllowAnyHeader()
                            .AllowAnyMethod()
                            .AllowCredentials();
                            //.WithMethods("OPTIONS", "GET");
                      });
});

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();

var app = builder.Build();
app.UseHttpsRedirection();

app.UseCors(apiCorsPolicy);

app.UseAuthorization();
app.MapControllers();
app.Run();

here more examples

LeonardoX
  • 1,113
  • 14
  • 31
  • Just a note for other .Net newbies who don't know which files do what, this goes in `//Program.cs` (at least when following the SignalR example on Microsofts website). – Magnus Sep 05 '22 at 09:56
  • 1
    However, this doesn't "kick in" until you've [EnableCors] in your controller. Until then CORS does nothing. – Fandango68 Dec 16 '22 at 05:14
  • @Fandango68 that is not true if you properly set that up. Unless you want to enable it for only specific controllers OR you are using endpoint for per routes. Check this https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-7.0#enable-cors-with-attributes – curiousBoy May 04 '23 at 07:04
13

To expand on user8266077's answer, I found that I still needed to supply OPTIONS response for preflight requests in .NET Core 2.1-preview for my use case:

// https://stackoverflow.com/a/45844400
public class CorsMiddleware
{
  private readonly RequestDelegate _next;

  public CorsMiddleware(RequestDelegate next)
  {
    _next = next;
  }

  public async Task Invoke(HttpContext context)
  {
    context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
    context.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
    // Added "Accept-Encoding" to this list
    context.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Accept-Encoding, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
    context.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");
    // New Code Starts here
    if (context.Request.Method == "OPTIONS")
    {
      context.Response.StatusCode = (int)HttpStatusCode.OK;
      await context.Response.WriteAsync(string.Empty);
    }
    // New Code Ends here

    await _next(context);
  }
}

and then enabled the middleware like so in Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
  app.UseMiddleware(typeof(CorsMiddleware));
  // ... other middleware inclusion such as ErrorHandling, Caching, etc
  app.UseMvc();
}
ckr
  • 131
  • 2
  • 3
  • 2
    I recommend adding middleware that way: `app.Use();` – Albert221 Sep 24 '18 at 13:38
  • You can replace those 2 ligne : context.Response.StatusCode = (int)HttpStatusCode.OK; await context.Response.WriteAsync(string.Empty); with a simple : return; – Hayha Oct 18 '18 at 22:27
  • 1
    To 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. – Adam Jan 05 '19 at 00:03
11

for ASP.NET Core 3.1 this soleved my Problem https://jasonwatmore.com/post/2020/05/20/aspnet-core-api-allow-cors-requests-from-any-origin-and-with-credentials

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors();
            services.AddControllers();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseRouting();

            // global cors policy
            app.UseCors(x => x
                .AllowAnyMethod()
                .AllowAnyHeader()
                .SetIsOriginAllowed(origin => true) // allow any origin
                .AllowCredentials()); // allow credentials

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

            app.UseEndpoints(x => x.MapControllers());
        }
    }
H.Azizkhani
  • 893
  • 10
  • 11
7

None of the above procedures helped and I then read article which solved the issue.

Below is the code.

public void ConfigureServices(IServiceCollection services)
{
    // Add service and create Policy with options
    services.AddCors(options =>
    {
        options.AddPolicy("CorsPolicy",
            builder => builder.AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials() );
    });


    services.AddMvc(); 
}

and

public void Configure(IApplicationBuilder app)
{
    // ...

    // global policy - assign here or on each controller
    app.UseCors("CorsPolicy");

and on the top of my actionmethod

[EnableCors("CorsPolicy")]
Sainath
  • 979
  • 2
  • 13
  • 22
  • 3
    This 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: https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.1: `Use the [EnableCors] attribute or middleware, not both in the same app.` – FoggyDay Dec 08 '19 at 23:31
  • @FoggyDay - not quite correct. You can app.UseCors() with multiple policies and multiple [EnableCors("policyA")] in your controllers. Albeit it's 2022 now. More here https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-7.0 – Fandango68 Dec 16 '22 at 05:22
6

Simplest solution is add

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseCors(options => options.AllowAnyOrigin());

        app.UseHttpsRedirection();
        app.UseMvc();
    }

to Startup.cs.

amilamad
  • 470
  • 6
  • 9
5

For me the solution was to correct the order:

app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
Rakesh Singh
  • 51
  • 1
  • 1
5

Here's a .NET 6 example of a Program.cs file using top-level statements to configure CORS. As can be seen, builder.Services.AddCors and app.UseCors are the required statements. The two commented UseCors statements also work and were included to show other options. I made no changes to my ASP.NET API controllers.

For reference, my development Angular app is running on localhost:4200 and is connecting to the development ASP.NET API server using https://localhost:7262.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddCors();
var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

//app.UseCors(options => options.WithOrigins("http://localhost:4200").AllowAnyMethod());
//app.UseCors(options => options.WithOrigins("http://localhost:4200").WithMethods(new string[] {"POST", "PUT"}));
app.UseCors(options => options.AllowAnyOrigin().AllowAnyMethod());

app.MapControllers();

app.Run();
Goal Man
  • 171
  • 2
  • 6
4

try adding jQuery.support.cors = true; before the Ajax call

It could also be that the data your sending to the API is wonky,

try adding the following JSON function

        var JSON = JSON || {};

    // implement JSON.stringify serialization
    JSON.stringify = JSON.stringify || function (obj) {

        var t = typeof (obj);
        if (t != "object" || obj === null) {

            // simple data type
            if (t == "string") obj = '"' + obj + '"';
            return String(obj);

        }
        else {

            // recurse array or object
            var n, v, json = [], arr = (obj && obj.constructor == Array);

            for (n in obj) {
                v = obj[n]; t = typeof (v);

                if (t == "string") v = '"' + v + '"';
                else if (t == "object" && v !== null) v = JSON.stringify(v);

                json.push((arr ? "" : '"' + n + '":') + String(v));
            }

            return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
        }
    };

    // implement JSON.parse de-serialization
    JSON.parse = JSON.parse || function (str) {
        if (str === "") str = '""';
        eval("var p=" + str + ";");
        return p;
    };

then in your data: object change it to

    data: JSON.stringify({
        username: username,
        password: password
    }),
Hossein Narimani Rad
  • 31,361
  • 18
  • 86
  • 116
  • Thanks for your help. Definitely utilized a portion of the answer to figure out the solution in the end after combining everyones answers – killerrin Jun 08 '17 at 01:27
4

I think if you use your own CORS middleware you need to make sure it is really CORS request by checking origin header.

 public class CorsMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IMemoryCache _cache;
    private readonly ILogger<CorsMiddleware> _logger;

    public CorsMiddleware(RequestDelegate next, IMemoryCache cache, ILogger<CorsMiddleware> logger)
    {
        _next = next;
        _cache = cache;
        _logger = logger;
    }
    public async Task InvokeAsync(HttpContext context, IAdministrationApi adminApi)
    {
        if (context.Request.Headers.ContainsKey(CorsConstants.Origin) || context.Request.Headers.ContainsKey("origin"))
        {
            if (!context.Request.Headers.TryGetValue(CorsConstants.Origin, out var origin))
            {
                context.Request.Headers.TryGetValue("origin", out origin);
            }

            bool isAllowed;
            // Getting origin from DB to check with one from request and save it in cache 
            var result = _cache.GetOrCreateAsync(origin, async cacheEntry => await adminApi.DoesExistAsync(origin));
            isAllowed = result.Result.Result;

            if (isAllowed)
            {
                context.Response.Headers.Add(CorsConstants.AccessControlAllowOrigin, origin);
                context.Response.Headers.Add(
                    CorsConstants.AccessControlAllowHeaders,
                    $"{HeaderNames.Authorization}, {HeaderNames.ContentType}, {HeaderNames.AcceptLanguage}, {HeaderNames.Accept}");
                context.Response.Headers.Add(CorsConstants.AccessControlAllowMethods, "POST, GET, PUT, PATCH, DELETE, OPTIONS");

                if (context.Request.Method == "OPTIONS")
                {
                    _logger.LogInformation("CORS with origin {Origin} was handled successfully", origin);
                    context.Response.StatusCode = (int)HttpStatusCode.NoContent;
                    return;
                }

                await _next(context);
            }
            else
            {
                if (context.Request.Method == "OPTIONS")
                {
                    _logger.LogInformation("Preflight CORS request with origin {Origin} was declined", origin);
                    context.Response.StatusCode = (int)HttpStatusCode.NoContent;
                    return;
                }

                _logger.LogInformation("Simple CORS request with origin {Origin} was declined", origin);
                context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
                return;
            }
        }

        await _next(context);
    }
Riddik
  • 2,565
  • 1
  • 11
  • 21
  • Thank 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 the `Origin` header. This saved my day! (Or at least my forenoon ;) ) – Paul Kertscher Jul 08 '19 at 07:04
4

For me, it had nothing to do with the code that I was using. For Azure we had to go into the settings of the App Service, on the side menu the entry "CORS". There I had to add the domain that I was requesting stuff from. Once I had that in, everything was magic.

kjbetz
  • 121
  • 4
  • 1
    Oh 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! – Rich Freeman Nov 26 '21 at 13:51
4

.NET Core 3.1

Worked for me and how the docs say to do it:

in Startup class:

readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins"; 

In ConfigureServices() method:

    services.AddCors(options =>
    {
        options.AddPolicy(MyAllowSpecificOrigins,
        builder =>
        {
            builder.WithOrigins("http://example.com",
                                "http://www.contoso.com");
        });
    });

In Configure() method:

    app.UseCors(MyAllowSpecificOrigins);  

https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.1

Andrew
  • 18,680
  • 13
  • 103
  • 118
3

In launchSettings.json, under iisSettings, set anonymousAuthentication to true:

"iisSettings": {
    "windowsAuthentication": true,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:4200/",
      "sslPort": 0
    }
  }

Then, in Startup.cs, under ConfigureServices, before services.AddMvc, add:

services.AddCors(options => options.AddPolicy("ApiCorsPolicy", builder =>
{
    builder
        .AllowAnyOrigin()
        .WithHeaders(HeaderNames.AccessControlAllowHeaders, "Content-Type")
        .AllowAnyMethod()
        .AllowCredentials();
}));

and then, in configure method, before app.UseMvc() add:

app.UseCors("ApiCorsPolicy");
Adrian
  • 121
  • 2
  • 12
  • This 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!. – HaRoLD Aug 26 '19 at 22:24
2

Based on your comment in MindingData's answer, it has nothing to do with your CORS, it's working fine.

Your Controller action is returning the wrong data. HttpCode 415 means, "Unsupported Media type". This happens when you either pass the wrong format to the controller (i.e. XML to a controller which only accepts json) or when you return a wrong type (return Xml in a controller which is declared to only return xml).

For later one check existence of [Produces("...")]attribute on your action

Tseng
  • 61,549
  • 15
  • 193
  • 205
  • Thanks 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 – killerrin Jun 08 '17 at 01:31
2

I'm using .Net CORE 3.1 and I spent ages banging my head against a wall with this one when I realised that my code has started actually working but my debugging environment was broken, so here's 2 hints if you're trying to troubleshoot the problem:

  1. If you're trying to log response headers using ASP.NET middleware, the "Access-Control-Allow-Origin" header will never show up even if it's there. I don't know how but it seems to be added outside the pipeline (in the end I had to use wireshark to see it).

  2. .NET CORE won't send the "Access-Control-Allow-Origin" in the response unless you have an "Origin" header in your request. Postman won't set this automatically so you'll need to add it yourself.

Andy
  • 10,412
  • 13
  • 70
  • 95
2

Here is my code : )

  app.Use((ctx, next) =>
        {
            ctx.Response.Headers.Add("Access-Control-Allow-Origin", ctx.Request.Headers["Origin"]);
            ctx.Response.Headers.Add("Access-Control-Allow-Methods", "*");
            ctx.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
            ctx.Response.Headers.Add("Access-Control-Allow-Headers", "AccessToken,Content-Type");
            ctx.Response.Headers.Add("Access-Control-Expose-Headers", "*");
            if (ctx.Request.Method.ToLower() == "options")
            {
                ctx.Response.StatusCode = 204;

                return Task.CompletedTask;
            }
            return next();
        });
Lnn
  • 59
  • 5
2

In my case I fixed with UseCors before UserRouting..

  • I 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. – Brandonm Jul 13 '20 at 07:42
1

Simple and easy way to do it.

  1. Install package

Install-Package Microsoft.AspNetCore.Cors

  1. Put this below code in startup.cs file

app.UseCors(options => options.AllowAnyOrigin());

Cray
  • 2,774
  • 7
  • 22
  • 32
pintu sharma
  • 171
  • 1
  • 3
1

Here is how I did this.

I see that in some answers they are setting app.UserCors("xxxPloicy") and putting [EnableCors("xxxPloicy")] in controllers. You do not need to do both.

Here are the steps.

In Startup.cs inside the ConfigureServices add the following code.

    services.AddCors(c=>c.AddPolicy("xxxPolicy",builder => {
        builder.AllowAnyOrigin()
        .AllowAnyMethod()
        .AllowAnyHeader();
    }));

If you want to apply all over the project then add the following code in Configure method in Startup.cs

app.UseCors("xxxPolicy");

Or

If you want to add it to the specific controllers then add enable cors code as shown below.

[EnableCors("xxxPolicy")]
[Route("api/[controller]")]
[ApiController]
public class TutorialController : ControllerBase {}

For more info: see this

Arshath Shameer
  • 453
  • 4
  • 15
1

Use a custom Action/Controller Attribute to set the CORS headers.

Example:

public class AllowMyRequestsAttribute : ControllerAttribute, IActionFilter
{
    public void OnActionExecuted(ActionExecutedContext context)
    {
        // check origin
        var origin = context.HttpContext.Request.Headers["origin"].FirstOrDefault();
        if (origin == someValidOrigin)
        {
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin", origin);
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Headers", "*");
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Methods", "*");
            // Add whatever CORS Headers you need.
        }
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        // empty
    }
}

Then on the Web API Controller / Action:

[ApiController]
[AllowMyRequests]
public class MyController : ApiController
{
    [HttpGet]
    public ActionResult<string> Get()
    {
        return "Hello World";
    }
}
warrickh
  • 1,616
  • 1
  • 16
  • 14
1

In my case character / at the end of my origin name was causing an issue.

Solution that worked out for me in .NET Core 3.1:

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(c => c.AddPolicy("PolicyName", policy => {
        policy.WithOrigins("http://localhost:3000")
        .AllowAnyMethod()
        .AllowAnyHeader();
    }));
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseCors("PolicyName");
}
1

The solution that worked for me in ASP.NET Core 3.1:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors(options =>
            {
                options.AddPolicy("CorsPolicy",
                    builder => builder.AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader());
            });
            services.AddControllersWithViews();
        }

and then change the following:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseCors("CorsPolicy");

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }
            app.UseHttpsRedirection();
            app.UseStaticFiles();

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

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }

Then program worked and error was solved.

Dominik
  • 1,366
  • 2
  • 18
  • 37
0

I got MindingData's answer above to work, but I had to use Microsoft.AspNet.Cors instead of Microsoft.AspNetCore.Cors. I am using .NetCore Web Application API project in Visual Studio 2019

carl
  • 33
  • 5
  • 2
    NOTE: 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 Dec 08 '19 at 23:27
0

The

Microsoft.AspNetCore.Cors

will allow you to do CORS with built-in features, but it does not handle OPTIONS request. The best workaround so far is creating a new Middleware as suggested in a previous post. Check the answer marked as correct in the following post:

Enable OPTIONS header for CORS on .NET Core Web API

Bonomi
  • 2,541
  • 5
  • 39
  • 51
0

Just to add to answer here, if you are using app.UseHttpsRedirection(), and you are hitting not SSL port consider commenting out this.

Raj
  • 264
  • 1
  • 3
  • 18
0

I was using blazor webassembly as client and asp.net web api core as backend and had cors problem too.

I found solution with these code:

My ASP.Net core web api Startup.cs ConfigureServices and Configure methods first lines looks like this:

public void ConfigureServices(IServiceCollection services)
{
   services.AddCors(options => options.AddPolicy("ApiCorsPolicy", builder =>
   {
        builder.WithOrigins("http://example.com").AllowAnyMethod().AllowAnyHeader();
    }));

 //other code below...
}

and my Configure method:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseCors(
        options =>   options.WithOrigins("http://example.com").AllowAnyMethod().AllowAnyHeader()
            );
 //other code below...
}

change http://example.com with your client domain or ip address

Zviadi
  • 81
  • 1
  • 5
0

below is the settings which works for me: enter image description here

Jaydeep Shil
  • 1,894
  • 22
  • 21
0

For me it started working when i have set explicitly the headers that I was sending. I was adding the content-type header, and then it worked.

.net

.WithHeaders("Authorization","Content-Type")

javascript:

this.fetchoptions = {
        method: 'GET', 
        cache: 'no-cache', 
        credentials: 'include', 
        headers: {
            'Content-Type': 'application/json',
        },
        redirect: 'follow', 
    }; 
Emmanuel
  • 7,574
  • 3
  • 24
  • 22
0

AspNetCoreModuleV2 cannot handle OPTIONS causing a preflight issue

I discovered that .net core module does not handle OPTIONS well which makes a big CORS problem:

Solution: remove the star *

In web.config, exclude OPTIONS verb from the module because this verb is already handled by the IIS OPTIONSVerbHandler:

 <add name="aspNetCore" path="*" verb="* modules="AspNetCoreModuleV2" resourceType="Unspecified" />

with this one

<add name="aspNetCore" path="*" verb="GET,POST,PUT,DELETE" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
Shadi Alnamrouti
  • 11,796
  • 4
  • 56
  • 54
0

if CORS policy occurred you can see that in inspect element => network … to handle this, you can introduce your client app URL or ip/port to .NET core app

var  MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      policy  =>
                      {
                          policy.WithOrigins("http://example.com",
                                              "http://www.contoso.com");
                      });
});

// services.AddResponseCaching();

builder.Services.AddControllers();

var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseCors(MyAllowSpecificOrigins);

app.UseAuthorization();

app.MapControllers();

app.Run();

please read more : https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-7.0

-1
  1. Please go the the project properties
  2. checked the Enable Anonymous Authentication It is working fine for me. enter image description here The image shows the

enter image description here

Md Nazrul Islam
  • 363
  • 4
  • 13