Reputation: 3557
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"));
Upvotes: 341
Views: 574594
Reputation: 6139
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseCors(builder => builder
.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed((host) => true)
.AllowCredentials()
);
}
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
}
Edit as per 2025-02-01:
To enable only specific URLs to use your API:
in program.cs
var builder = WebApplication.CreateBuilder(args);
// some stuff
var app = builder.Build();
var services = builder.Services;
var corsUrls = ["http://localhost:4200"]; // here change or add your urls
if (corsUrls == null)
{
throw new Exception("CorsUrls not found in appsettings.json");
}
services.AddCors(options =>
{
options.AddPolicy("CorsApi", builder =>
{
builder.WithOrigins(corsUrls)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
});
}
app.UseRouting();
app.UseCors("CorsApi"); // don't forget to use the cors policy
Upvotes: 48
Reputation: 9
builder.Services.AddCors(p => p.AddPolicy("corspolicy", build =>
{
build.WithOrigins("*").AllowAnyMethod().AllowAnyHeader();
}));
app.UseCors("corspolicy");
Upvotes: 0
Reputation: 1293
For .Net 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
Upvotes: 21
Reputation: 1
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
Upvotes: 0
Reputation: 373
Upvotes: -1
Reputation: 191
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();
Upvotes: 6
Reputation: 61
For me the solution was to correct the order:
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
Upvotes: 6
Reputation: 13248
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" />
Upvotes: 0
Reputation: 8622
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',
};
Upvotes: 0
Reputation: 923
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());
}
}
Upvotes: 13
Reputation: 934
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.
Upvotes: 18
Reputation: 81
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.
Upvotes: 1
Reputation: 354
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");
}
Upvotes: 1
Reputation: 3297
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
Upvotes: 303
Reputation: 121
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
Upvotes: 0
Reputation: 374
Just to add to answer here, if you are using app.UseHttpsRedirection()
, and you are hitting not SSL port consider commenting out this.
Upvotes: 0
Reputation: 1646
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";
}
}
Upvotes: 1
Reputation: 453
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
Upvotes: 1
Reputation: 21
In my case I fixed with UseCors before UserRouting..
Upvotes: 2
Reputation: 69
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();
});
Upvotes: 3
Reputation: 11462
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:
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).
.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.
Upvotes: 3
Reputation: 169
Simple and easy way to do it.
Install-Package Microsoft.AspNetCore.Cors
app.UseCors(options => options.AllowAnyOrigin());
Upvotes: 1
Reputation: 2733
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
Upvotes: 0
Reputation: 20061
.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
Upvotes: 4
Reputation: 121599
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 higherhttps
. 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()
aboveapp.UseEndpoints(endpoints => endpoints.MapControllers())
.
Upvotes: 25
Reputation: 141
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");
Upvotes: 5
Reputation: 480
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.
Upvotes: 7
Reputation: 33
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
Upvotes: 0
Reputation: 12460
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/
Upvotes: 342