Configuring CORS in ASP.NET Core
1. Prerequisites
If you are not familiar with the Same-Origin Policy (SOP) or the Cross-Origin Resource Sharing (CORS) policy, I highly recommend studying my previous post where I explained SOP and CORS in detail. This post assumes you have a general understanding of these policies and focuses solely on configuring CORS in an ASP.NET Core environment.
If you’re here to resolve an error you’re encountering, I urge you to understand the problem and the involved policies before focusing on resolving the error itself.
2. Configuring CORS
Configuring CORS in an ASP.NET Core project to enable cross-origin requests involves adding CORS services to the service container, and then either registering the CORS middleware in the pipeline, using CORS attributes or utilizing endpoint routing to enable CORS.
2.1. Service Registration & Policy Configurations
The first step to configuring CORS policy in an ASP.NET Core application is to add the CORS services to the project. This is achieved using the AddCors() method, which takes CORS settings as input and registers all necessary services (which, if you are curious, includes the CORS service itself, a default policy provider, and various options-related services).
With the AddCors() call, you can register as many policies as needed.
var builder = WebApplication.CreateBuilder(args);
// ...
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "AllowAll",
configurePolicy: policy =>
{
policy.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
options.AddPolicy(name: "AllowOnlySomeOrigins",
configurePolicy: policy =>
{
policy.WithOrigins("<https://example1.com>",
"<https://example2.com>");
});
});
// ...
var app = builder.Build();
// ...
In this case, we registered two policies which are named AllowAll and AllowOnlySomeOrigins. The AllowAll policy is configured to essentially disable CORS policy, and the AllowOnlySomeOrigins is configured to only allow cross-origin requests from example1.com and example2.com.
All CORS settings will be explained in detail later in this post.
The next step is to enable CORS using a policy, which will be explained in the upcoming section. Typically, when using the middleware approach, you will only need and use a single policy.
2.2. Middleware Registration
To enable CORS, you can either register the built-in CORS middleware with UseCors() which enables CORS across all endpoints, or you can use endpoint routing with RequireCors() to enable CORS only for specific endpoints. Bot of these approaches are explained in the upcoming sections.
The CORS middleware uses the CORS services you added to the service container to enable CORS policy across all endpoints in the project. The CORS middleware is registered with the UseCors() method, which optionally takes policy name as parameter.
For example;
// ...
var myPolicyName = "MyPolicyName"; // you will specify the exact same string in different places, so assigning policy names to variables avoids potential typo mistakes.
builder.Services.AddCors(options =>
{
options.AddPolicy(name: myPolicyName,
configurePolicy: policy =>
{
policy.WithOrigins("<http://example1.com>",
"<http://example2.com>");
});
});
// ...
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
**app.UseCors(**myPolicyName**);**
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
// ...
2.2.1. Using Default Policy
By explicitly specifying the default policy with AddDefaultPolicy(), you can then use UseCors() or RequireCors() without needing to specify a policy name as a parameter. Additionally, with a default policy set, you can use the [EnableCors] attribute without having to specify a policy name as well. The idea is that, when a default policy is set, the CORS middleware and services will know which policy to use when a policy is not explicitly specified.
Note that even if you have only one policy registered, simply calling UseCors() without specifying a policy name will not enable CORS. Therefore, you need to call AddDefaultPolicy() for atleast one policy definition if you don’t wish to provide a policy name for UseCors(), RequireCors(), or [EnableCors].
Adding a default policy is exactly the same as adding any policy, except you call AddDefaultPolicy() instead of AddPolicy().
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(
policy =>
{
policy.WithOrigins("<http://example.com>");
});
});
2.2.2. Regarding Middleware Order
As always with registering middlewares, you must be cautious about the placement of the CORS middleware in the pipeline. For example, you would not want to call UseResponseCaching() (if you are using response caching) before the CORS middleware.
2.2.2.1. Important Note for JavaScript Clients
Typically, UseStaticFiles() is called before the UseCors(). However, when using JavaScript clients (e.g., Angular, React), you must call UseCors() before UseStaticFiles().
2.3. Enabling CORS With Attributes
As I’ve mentioned, using the middleware approach ensures the same CORS policy across all endpoints in the project. However, if you require fine-grained control over which endpoints have CORS enabled and with what policy, you can use the [EnableCors] attribute.
It’s important to note that the need for this level of control is rare, and you most likely won’t need to configure CORS on specific endpoints using attributes.
The [EnableCors] attribute can be applied to razor page PageModels, controllers or controller action methods. You can use [EnableCors] to specify the default policy, or *[EnableCors("{PolicyName}")]* to specify a particular policy.
💡 When the
[EnableCors]attribute is applied to an endpoint AND the CORS middleware is registered in pipeline, both of the policies are applied. However, this is not recommended. You should choose either of the approaches and not combine them.
Here is how you can enable CORS with a specific policy on a controller action:
public classController : Controller
{
// ...
[EnableCors("PolicyName")]
public ActionResult<string> FunCatFact()
{
return "A group of cats is called a clowder.";
}
// ...
}
2.3.1. [DisableCors] Attribute
The [DisableCors] attribute can be used when using CORS middleware (UseCors()) to disable CORS policy for specific endpoints, or when you have [EnableCors] on controller-level and want to disable CORS on specific controller actions. For example:
[EnableCors] // if there is a default policy set, you don't have to specify policy name
public class CatController : Controller
{
// ...
[DisableCors] // this will disable CORS for this action
public ActionResult<string> FunCatFact()
{
return "A group of cats is called a clowder";
}
// this action will have CORS enabled, since it was enabled on the controller
public ActionResult<string> FunDogFact()
{
return "Dogs dream just like humans do (apparently)";
}
// ...
}
3. CORS Settings Explained In-Detail
3.1. Allowing Origins
- AllowAnyOrigin: Allows cross-origin requests from all origins, accepting any scheme (accepting both http and https). Using this setting is highly discouraged. Effect;
Access-Control-Allow-Origin: *header gets added to CORS responses. Usage;policy.AllowAnyOrigin() - WithOrigins: Specifies a list of origins that are allowed to initiate cross-domain requests. Effect;
Access-Control-Allow-Originheader gets added to CORS responses. Usage;policy.WithOrigins("<http://example1.com>", "<http://example2.com>")
3.2. Allowing Methods
- AllowAnyMethod: Allows any HTTP method. Effect;
Access-Control-Allow-Methods: *header gets added to CORS responses. Usage;policy.AllowAnyMethod() - WithMethods: Specifies a list of methods to be allowed in cross-origin requests. Effect;
Access-Control-Allow-Methodsheader gets added to CORS responses. Usage;policy.WithMethods("GET", "POST")
3.3. Allowing Headers
- AllowAllHeaders: Simply allows all headers in cross-origin requests. Effect;
Access-Control-Allow-Headers: *header gets added to CORS responses. Usage;policy.AllowAnyHeader() - WithHeaders: Specifies a list of headers that are accepted in cross-origin requests. Effect;
Access-Control-Allow-Headersheader gets added to the CORS responses. Usage;policy.WithHeaders(HeaderNames.AcceptCharset, "X-MyCustomHeader", "X-MyOtherCustomHeader")

You can use “HeaderNames” to specify known HTTP headers.
- WithExposedHeaders: Specifies a list of headers that can be exposed/shown to the calling script. By default, browsers will filter out all non-CORS-safelisted headers from the responses. Effect; Access-Control-Expose-Headers header gets added to CORS responses. Usage; policy.WithExposedHeaders(“X-MyCustomHeader”, “X-MyOtherCustomHeader”)
3.4. Allowing/Disallowing Credentialed Requests
- AllowCredentials: Specifies whether credentialed requests are allowed. Effect; Access-Control-Allow-Credentials: true header gets added to CORS responses. Usage; policy.AllowCredentials()
- DisallowCredentials: Sets the policy to not accept credentialed requests. Effect; Access-Control-Allow-Credentials: false header gets added to CORS responses. Usage; policy.DisallowCredentials()
3.5. Setting Preflight Cache Duration
-
SetPreflightMaxAge: Specifies the duration for which the preflight response can be cached. Effect; Access-Control-Max-Age header gets added to CORS responses, where 55 is an example amount. Usage; policy.SetPreflightMaxAge(TimeSpan.FromSeconds(55))
If you called AllowCredentials, you can’t also call AllowAnyOrigin, AllowAnyMethod, or AllowAllHeaders on the same policy because CORS spec prohibits any wildcards in credentialed requests.
4. Offloading CORS to IIS
Just as you can delegate tasks like HSTS and HTTPS redirection to IIS, you can also delegate the management of CORS policies to the web server.
When CORS is configured on IIS, you can make changes to CORS settings, not requiring versioning (you can achieve same flexibility with coding CORS in the app by reading CORS settings from appsettings.json).
Moreover, if the server doesn’t allow anonymous access, CORS needs to run before Windows Authentication will have to run before CORS. The IIS CORS module makes this possible.
On the other hand, you will not be able to run your projects locally. For this reason, even if you choose to offload CORS to IIS in production, you will still need to register CORS services and middleware conditionally in your code by checking the current development environment.
You can install IIS CORS module from https://www.iis.net/downloads/microsoft/iis-cors-module.