This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

Download Microsoft Edge More info about Internet Explorer and Microsoft Edge

Important

This information relates to a pre-release product that may be substantially modified before it's commercially released. Microsoft makes no warranties, express or implied, with respect to the information provided here.

For the current release, see the .NET 7 version of this article .

By Rick Anderson and Kirk Larkin

This article shows how to enable CORS in an ASP.NET Core app.

Browser security prevents a web page from making requests to a different domain than the one that served the web page. This restriction is called the same-origin policy . The same-origin policy prevents a malicious site from reading sensitive data from another site. Sometimes, you might want to allow other sites to make cross-origin requests to your app. For more information, see the Mozilla CORS article .

Cross Origin Resource Sharing (CORS):

  • Is a W3C standard that allows a server to relax the same-origin policy.
  • Is not a security feature, CORS relaxes security. An API is not safer by allowing CORS. For more information, see How CORS works .
  • Allows a server to explicitly allow some cross-origin requests while rejecting others.
  • Is safer and more flexible than earlier techniques, such as JSONP .
  • View or download sample code ( how to download )

    Same origin

    Two URLs have the same origin if they have identical schemes, hosts, and ports ( RFC 6454 ).

    These two URLs have the same origin:

  • https://example.com/foo.html
  • https://example.com/bar.html
  • These URLs have different origins than the previous two URLs:

  • https://example.net : Different domain
  • https://www.example.com/foo.html : Different subdomain
  • http://example.com/foo.html : Different scheme
  • https://example.com:9000/foo.html : Different port
  • Enable CORS

    There are three ways to enable CORS:

  • In middleware using a named policy or default policy .
  • Using endpoint routing .
  • With the [EnableCors] attribute.
  • Using the [EnableCors] attribute with a named policy provides the finest control in limiting endpoints that support CORS.

    Warning

    UseCors must be called in the correct order. For more information, see Middleware order . For example, UseCors must be called before UseResponseCaching when using UseResponseCaching .

    Each approach is detailed in the following sections.

    CORS with named policy and middleware

    CORS Middleware handles cross-origin requests. The following code applies a CORS policy to all the app's endpoints with the specified origins:

    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();
    

    The preceding code:

  • Sets the policy name to _myAllowSpecificOrigins. The policy name is arbitrary.
  • Calls the UseCors extension method and specifies the _myAllowSpecificOrigins CORS policy. UseCors adds the CORS middleware. The call to UseCors must be placed after UseRouting, but before UseAuthorization. For more information, see Middleware order.
  • Calls AddCors with a lambda expression. The lambda takes a CorsPolicyBuilder object. Configuration options, such as WithOrigins, are described later in this article.
  • Enables the _myAllowSpecificOrigins CORS policy for all controller endpoints. See endpoint routing to apply a CORS policy to specific endpoints.
  • When using Response Caching Middleware, call UseCors before UseResponseCaching.
  • With endpoint routing, the CORS middleware must be configured to execute between the calls to UseRouting and UseEndpoints.

    See Test CORS for instructions on testing code similar to the preceding code.

    The AddCors method call adds CORS services to the app's service container:

    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();
    

    For more information, see CORS policy options in this document.

    The CorsPolicyBuilder methods can be chained, as shown in the following code:

    var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddCors(options =>
        options.AddPolicy(MyAllowSpecificOrigins,
                              policy =>
                                  policy.WithOrigins("http://example.com",
                                                      "http://www.contoso.com")
                                                      .AllowAnyHeader()
                                                      .AllowAnyMethod();
    builder.Services.AddControllers();
    var app = builder.Build();
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    app.UseCors(MyAllowSpecificOrigins);
    app.UseAuthorization();
    app.MapControllers();
    app.Run();
    

    Note: The specified URL must not contain a trailing slash (/). If the URL terminates with /, the comparison returns false and no header is returned.

    Warning

    UseCors must be placed after UseRouting and before UseAuthorization. This is to ensure that CORS headers are included in the response for both authorized and unauthorized calls.

    UseCors and UseStaticFiles order

    Typically, UseStaticFiles is called before UseCors. Apps that use JavaScript to retrieve static files cross site must call UseCors before UseStaticFiles.

    CORS with default policy and middleware

    The following highlighted code enables the default CORS policy:

    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddCors(options =>
        options.AddDefaultPolicy(
            policy =>
                policy.WithOrigins("http://example.com",
                                    "http://www.contoso.com");
    builder.Services.AddControllers();
    var app = builder.Build();
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    app.UseCors();
    app.UseAuthorization();
    app.MapControllers();
    app.Run();
    

    The preceding code applies the default CORS policy to all controller endpoints.

    Enable Cors with endpoint routing

    With endpoint routing, CORS can be enabled on a per-endpoint basis using the RequireCors set of extension methods:

    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");
    builder.Services.AddControllers();
    builder.Services.AddRazorPages();
    var app = builder.Build();
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    app.UseCors();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
        endpoints.MapGet("/echo",
            context => context.Response.WriteAsync("echo"))
            .RequireCors(MyAllowSpecificOrigins);
        endpoints.MapControllers()
                 .RequireCors(MyAllowSpecificOrigins);
        endpoints.MapGet("/echo2",
            context => context.Response.WriteAsync("echo2"));
        endpoints.MapRazorPages();
    app.Run();
    

    In the preceding code:

  • app.UseCors enables the CORS middleware. Because a default policy hasn't been configured, app.UseCors() alone doesn't enable CORS.
  • The /echo and controller endpoints allow cross-origin requests using the specified policy.
  • The /echo2 and Razor Pages endpoints do not allow cross-origin requests because no default policy was specified.
  • The [DisableCors] attribute does not disable CORS that has been enabled by endpoint routing with RequireCors.

    In ASP.NET Core 7.0, the [EnableCors] attribute must pass a parameter or an ASP0023 Warning is generated from a ambiguous match on the route. ASP.NET Core 8.0 and later doesn't generate the ASP0023 warning.

    [Route("api/[controller]")]
    [ApiController]
    public class TodoItems2Controller : ControllerBase
        // OPTIONS: api/TodoItems2/5
        [HttpOptions("{id}")]
        public IActionResult PreflightRoute(int id)
            return NoContent();
        // OPTIONS: api/TodoItems2 
        [HttpOptions]
        public IActionResult PreflightRoute()
            return NoContent();
        [HttpPut("{id}")]
        public IActionResult PutTodoItem(int id)
            if (id < 1)
                return BadRequest();
            return ControllerContext.MyDisplayRouteInfo(id);
        // [EnableCors] // Not needed as OPTIONS path provided.
        [HttpDelete("{id}")]
        public IActionResult MyDelete(int id) =>
            ControllerContext.MyDisplayRouteInfo(id);
        // [EnableCors] //  Warning ASP0023 Route '{id}' conflicts with another action route.
        //                  An HTTP request that matches multiple routes results in an ambiguous
        //                  match error.
        [EnableCors("MyPolicy")] // Required for this path.
        [HttpGet]
        public IActionResult GetTodoItems() =>
            ControllerContext.MyDisplayRouteInfo();
        [HttpGet("{action}")]
        public IActionResult GetTodoItems2() =>
            ControllerContext.MyDisplayRouteInfo();
        [EnableCors("MyPolicy")]  // Required for this path.
        [HttpDelete("{action}/{id}")]
        public IActionResult MyDelete2(int id) =>
            ControllerContext.MyDisplayRouteInfo(id);
    

    See Test CORS with [EnableCors] attribute and RequireCors method for instructions on testing code similar to the preceding.

    Enable CORS with attributes

    Enabling CORS with the [EnableCors] attribute and applying a named policy to only those endpoints that require CORS provides the finest control.

    The [EnableCors] attribute provides an alternative to applying CORS globally. The [EnableCors] attribute enables CORS for selected endpoints, rather than all endpoints:

  • [EnableCors] specifies the default policy.
  • [EnableCors("{Policy String}")] specifies a named policy.
  • The [EnableCors] attribute can be applied to:

  • Razor Page PageModel
  • Controller
  • Controller action method
  • Different policies can be applied to controllers, page models, or action methods with the [EnableCors] attribute. When the [EnableCors] attribute is applied to a controller, page model, or action method, and CORS is enabled in middleware, both policies are applied. We recommend against combining policies. Use the [EnableCors] attribute or middleware, not both in the same app.

    The following code applies a different policy to each method:

    [Route("api/[controller]")]
    [ApiController]
    public class WidgetController : ControllerBase
        // GET api/values
        [EnableCors("AnotherPolicy")]
        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
            return new string[] { "green widget", "red widget" };
        // GET api/values/5
        [EnableCors("Policy1")]
        [HttpGet("{id}")]
        public ActionResult<string> Get(int id)
            return id switch
                1 => "green widget",
                2 => "red widget",
                _ => NotFound(),
    

    The following code creates two CORS policies:

    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddCors(options =>
        options.AddPolicy("Policy1",
            policy =>
                policy.WithOrigins("http://example.com",
                                    "http://www.contoso.com");
        options.AddPolicy("AnotherPolicy",
            policy =>
                policy.WithOrigins("http://www.contoso.com")
                                    .AllowAnyHeader()
                                    .AllowAnyMethod();
    builder.Services.AddControllers();
    var app = builder.Build();
    app.UseHttpsRedirection();
    app.UseRouting();
    app.UseCors();
    app.UseAuthorization();
    app.MapControllers();
    app.Run();
    

    For the finest control of limiting CORS requests:

  • Use [EnableCors("MyPolicy")] with a named policy.
  • Don't define a default policy.
  • Don't use endpoint routing.
  • The code in the next section meets the preceding list.

    See Test CORS for instructions on testing code similar to the preceding code.

    Disable CORS

    The [DisableCors] attribute does not disable CORS that has been enabled by endpoint routing.

    The following code defines the CORS policy "MyPolicy":

    var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddCors(options =>
        options.AddPolicy(name: "MyPolicy",
            policy =>
                policy.WithOrigins("http://example.com",
                                    "http://www.contoso.com")
                        .WithMethods("PUT", "DELETE", "GET");
    builder.Services.AddControllers();
    builder.Services.AddRazorPages();
    var app = builder.Build();
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    app.UseCors();
    app.UseAuthorization();
    app.UseEndpoints(endpoints => {
        endpoints.MapControllers();
        endpoints.MapRazorPages();
    app.Run();
    

    The following code disables CORS for the GetValues2 action:

    [EnableCors("MyPolicy")]
    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
        // GET api/values
        [HttpGet]
        public IActionResult Get() =>
            ControllerContext.MyDisplayRouteInfo();
        // GET api/values/5
        [HttpGet("{id}")]
        public IActionResult Get(int id) =>
            ControllerContext.MyDisplayRouteInfo(id);
        // PUT api/values/5
        [HttpPut("{id}")]
        public IActionResult Put(int id) =>
            ControllerContext.MyDisplayRouteInfo(id);
        // GET: api/values/GetValues2
        [DisableCors]
        [HttpGet("{action}")]
        public IActionResult GetValues2() =>
            ControllerContext.MyDisplayRouteInfo();
    

    The preceding code:

  • Doesn't enable CORS with endpoint routing.
  • Doesn't define a default CORS policy.
  • Uses [EnableCors("MyPolicy")] to enable the "MyPolicy" CORS policy for the controller.
  • Disables CORS for the GetValues2 method.
  • See Test CORS for instructions on testing the preceding code.

    CORS policy options

    This section describes the various options that can be set in a CORS policy:

  • Set the allowed origins
  • Set the allowed HTTP methods
  • Set the allowed request headers
  • Set the exposed response headers
  • Credentials in cross-origin requests
  • Set the preflight expiration time
  • AddPolicy is called in Program.cs. For some options, it may be helpful to read the How CORS works section first.

    Set the allowed origins

    AllowAnyOrigin: Allows CORS requests from all origins with any scheme (http or https). AllowAnyOrigin is insecure because any website can make cross-origin requests to the app.

    Specifying AllowAnyOrigin and AllowCredentials is an insecure configuration and can result in cross-site request forgery. The CORS service returns an invalid CORS response when an app is configured with both methods.

    AllowAnyOrigin affects preflight requests and the Access-Control-Allow-Origin header. For more information, see the Preflight requests section.

    SetIsOriginAllowedToAllowWildcardSubdomains: Sets the IsOriginAllowed property of the policy to be a function that allows origins to match a configured wildcard domain when evaluating if the origin is allowed.

    var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddCors(options =>
        options.AddPolicy(name: MyAllowSpecificOrigins,
            policy =>
                policy.WithOrigins("https://*.example.com")
                    .SetIsOriginAllowedToAllowWildcardSubdomains();
    builder.Services.AddControllers();
    var app = builder.Build();
    

    Set the allowed HTTP methods

    AllowAnyMethod:

  • Allows any HTTP method:
  • Affects preflight requests and the Access-Control-Allow-Methods header. For more information, see the Preflight requests section.
  • Set the allowed request headers

    To allow specific headers to be sent in a CORS request, called author request headers, call WithHeaders and specify the allowed headers:

    using Microsoft.Net.Http.Headers;
    var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddCors(options =>
        options.AddPolicy(name: MyAllowSpecificOrigins,
           policy =>
               policy.WithOrigins("http://example.com")
                      .WithHeaders(HeaderNames.ContentType, "x-custom-header");
    builder.Services.AddControllers();
    var app = builder.Build();
    

    To allow all author request headers, call AllowAnyHeader:

    var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddCors(options =>
        options.AddPolicy(name: MyAllowSpecificOrigins,
            policy =>
                policy.WithOrigins("https://*.example.com")
                       .AllowAnyHeader();
    builder.Services.AddControllers();
    var app = builder.Build();
    

    AllowAnyHeader affects preflight requests and the Access-Control-Request-Headers header. For more information, see the Preflight requests section.

    A CORS Middleware policy match to specific headers specified by WithHeaders is only possible when the headers sent in Access-Control-Request-Headers exactly match the headers stated in WithHeaders.

    For instance, consider an app configured as follows:

    app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
    

    CORS Middleware declines a preflight request with the following request header because Content-Language (HeaderNames.ContentLanguage) isn't listed in WithHeaders:

    Access-Control-Request-Headers: Cache-Control, Content-Language
    

    The app returns a 200 OK response but doesn't send the CORS headers back. Therefore, the browser doesn't attempt the cross-origin request.

    Set the exposed response headers

    By default, the browser doesn't expose all of the response headers to the app. For more information, see W3C Cross-Origin Resource Sharing (Terminology): Simple Response Header.

    The response headers that are available by default are:

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma
  • The CORS specification calls these headers simple response headers. To make other headers available to the app, call WithExposedHeaders:

    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddCors(options =>
        options.AddPolicy("MyExposeResponseHeadersPolicy",
            policy =>
                policy.WithOrigins("https://*.example.com")
                       .WithExposedHeaders("x-custom-header");
    builder.Services.AddControllers();
    var app = builder.Build();
    

    Credentials in cross-origin requests

    Credentials require special handling in a CORS request. By default, the browser doesn't send credentials with a cross-origin request. Credentials include cookies and HTTP authentication schemes. To send credentials with a cross-origin request, the client must set XMLHttpRequest.withCredentials to true.

    Using XMLHttpRequest directly:

    var xhr = new XMLHttpRequest();
    xhr.open('get', 'https://www.example.com/api/test');
    xhr.withCredentials = true;
    

    Using jQuery:

    $.ajax({
      type: 'get',
      url: 'https://www.example.com/api/test',
      xhrFields: {
        withCredentials: true
    

    Using the Fetch API:

    fetch('https://www.example.com/api/test', {
        credentials: 'include'
    

    The server must allow the credentials. To allow cross-origin credentials, call AllowCredentials:

    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddCors(options =>
        options.AddPolicy("MyMyAllowCredentialsPolicy",
            policy =>
                policy.WithOrigins("http://example.com")
                       .AllowCredentials();
    builder.Services.AddControllers();
    var app = builder.Build();
    

    The HTTP response includes an Access-Control-Allow-Credentials header, which tells the browser that the server allows credentials for a cross-origin request.

    If the browser sends credentials but the response doesn't include a valid Access-Control-Allow-Credentials header, the browser doesn't expose the response to the app, and the cross-origin request fails.

    Allowing cross-origin credentials is a security risk. A website at another domain can send a signed-in user's credentials to the app on the user's behalf without the user's knowledge.