Asp net core cors error

I am trying to enable cross origin resources sharing on my ASP.NET Core Web API, but I am stuck. The EnableCors attribute accepts policyName of type string as parameter: // Summary: // Creates ...

For «C# — ASP Net Core Web API (Net Core 3.1 LTS)», it worked for me …

In Startup.cs file:

Inside «ConfigureServices» function add this code:

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

Note: In case of «CorsPolicy» you can change for what you like or use global variable in «Startup» class.

Inside «Configure» function add this code:

app.UseCors("CorsPolicy");

Check the call order of the functions, it should look like this:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});          

And finally in your controller class add this code above your functions http:

[EnableCors("CorsPolicy")]

For example:

[EnableCors("CorsPolicy")]
[HttpPost("UserLoginWithGoogle")]
public async Task<ActionResult<Result>> UserLoginWithGoogle([FromBody] TokenUser tokenUser)
{            
    Result result = await usersGoogleHW.UserLoginWithGoogle(tokenUser.Token);
    return new JsonResult(result);
}

Note: «CorsPolicy» must match in the Startup and Controller.

Good luck …

Correctly configuring cross-origin resource sharing can be challenging. This post covers common CORS issues encountered while setting up a local development environment with ASP.NET Core Web API.

Disclaimer:  I am not an expert in configuring cross origin resource sharing (CORS).  This post is intended to be for learning purposes only and is not a guide to setting up CORS in a production environment. You should make sure you thoroughly understand the implications of the CORS settings for your site or API before making any changes.

This post shows how to use CORS settings to allow for cross-origin requests in a development environment only.

Enabling CORS is not a security feature! Adding exceptions for cross-origin resource sharing to your application decreases the overall security posture.  If your site will function correctly without enabling CORS support, you should leave it disabled.

The built-in middleware support for CORS in ASP.NET made it a breeze to setup (thanks ASP.NET team)! This was much easier than in earlier versions of ASP.NET.  Microsoft even has thorough documentation for setting up this middleware.

However, even with this robust middleware in place, I ran into some issues that I had to work through to get CORS fully functional.

In the context of a REST based Web API, cross-origin resource sharing allows pages that were served from a UI that has a different FQDN to call that Web API.  This can be very useful in development situations where the port of your UI application may be different than your API.  It is also helpful when you need to allow sub-domains that you trust to make calls directly to your API.

Pro Tip:  The preferred way to have third-party sites call your API is not to allow CORS but instead to have the third-party’s web pages call their own server and have their server call your API.  This way there is no CORS constraints imposed by the browser.

Initially, I configured the middleware by defining a simply policy in my startup.cs ConfigureServices method:

private readonly string AllowedOriginPolicy = "_AllowedOriginPolicy";

public void ConfigureServices(IServiceCollection services)
{  
    services.AddCors(options =>
    {
        options.AddPolicy(AllowedOriginPolicy,
            builder =>
            {
                var corsOrigins = new String[1]{ "https://localhost:1234" };

                builder.WithOrigins(corsOrigins);
            });
    });

    services.AddControllers();
}

You’ll notice that this policy creation is using a string array (there can be multiple allowed origins). The AllowedOriginPolicy is readonly string that identifies the policy when you wire it up in the Configure method:

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

    app.UseHttpsRedirection();

    app.UseRouting();

    app.UseCors(AllowedOriginPolicy);

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

Once this was done I thought CORS would be allowed between my local JavaScript based UI and API.  But I was wrong!

Troubleshooting I found the following issues that were preventing cross site requests in my local development environment:

  1. Needed methods and response headers were not allowed.
    In order for CORS to function correctly you need to allow the server to return any requested headers that are being requested by the fetch. There are a few that are returned by default, but if the client requests anything outside of this list then the request will be denied by the server. You also need to allow any HTTP methods you expect to be called (GET, POST, PUT, DELETE, OPTIONS).

Since I’m in a local development environment, I went ahead and allowed all methods and all headers:

services.AddCors(options =>
{
    options.AddPolicy(AllowedOriginPolicy,
        builder =>
        {
            var corsOrigins = new String[1]{ "https://localhost:1234" };

            builder.WithOrigins(corsOrigins)
                .AllowAnyHeader()
                .AllowAnyMethod();
        });
});

  1. Credential cookies were not allowed.
    By default, and for the safety of the user and site, the browser does not allow credential cookies to be sent on a CORS request. If your site uses authentication and the credential cookies need to be sent with the CORS request, it is necessary to enable this feature:
services.AddCors(options =>
{
    options.AddPolicy(AllowedOriginPolicy,
        builder =>
        {
            var corsOrigins = new String[1]{ "https://localhost:1234" };

            builder.WithOrigins(corsOrigins)
                .AllowCredentials()
                .AllowAnyHeader()
                .AllowAnyMethod();;
        });
});

  1. Fetch API not sending credentials.
    By default the Browser Fetch API will not send credentials to a different origin. In this case we had a web application using the Fetch API to send local REST requests to the ASP.NET Core Web API running on a different port. The browser was not sending the credentials used by the web application on the request.

The following option was set to allow Fetch to send the credentials cookie:

const response = await fetch(url, { credentials: 'include' });

This tells the fetch request to include the credential cookies even if the browser is making a cross-origin request.

MDN has great documentation on Using Fetch.

At this point the application was making CORS calls successfully in my development environment with the UI using one port and the API using another (different FQDNs).

title author description ms.author ms.custom ms.date uid

Enable Cross-Origin Requests (CORS) in ASP.NET Core

rick-anderson

Learn how CORS as a standard for allowing or rejecting cross-origin requests in an ASP.NET Core app.

riande

mvc

04/06/2022

security/cors

Enable Cross-Origin Requests (CORS) in ASP.NET Core

:::moniker range=»>= aspnetcore-6.0″

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]
xref:Microsoft.AspNetCore.Builder.CorsMiddlewareExtensions.UseCors%2A must be called in the correct order. For more information, see Middleware order. For example, UseCors must be called before xref:Microsoft.AspNetCore.Builder.ResponseCachingExtensions.UseResponseCaching%2A 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:

[!code-csharp]

The preceding code:

  • Sets the policy name to _myAllowSpecificOrigins. The policy name is arbitrary.
  • Calls the xref:Microsoft.AspNetCore.Builder.CorsMiddlewareExtensions.UseCors%2A 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 xref:Microsoft.Extensions.DependencyInjection.CorsServiceCollectionExtensions.AddCors%2A with a lambda expression. The lambda takes a xref:Microsoft.AspNetCore.Cors.Infrastructure.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 xref:Microsoft.AspNetCore.Builder.CorsMiddlewareExtensions.UseCors%2A before xref:Microsoft.AspNetCore.Builder.ResponseCachingExtensions.UseResponseCaching%2A.

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 xref:Microsoft.Extensions.DependencyInjection.MvcCorsMvcCoreBuilderExtensions.AddCors%2A method call adds CORS services to the app’s service container:

[!code-csharp]

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

The xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder methods can be chained, as shown in the following code:

[!code-csharp]

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

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:

[!code-csharp]

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

Enable Cors with endpoint routing

Enabling CORS on a per-endpoint basis using RequireCors does not support automatic preflight requests. For more information, see this GitHub issue and Test CORS with endpoint routing and [HttpOptions].

With endpoint routing, CORS can be enabled on a per-endpoint basis using the xref:Microsoft.AspNetCore.Builder.CorsEndpointConventionBuilderExtensions.RequireCors%2A set of extension methods:

[!code-csharp]

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.

See Test CORS with endpoint routing and [HttpOptions] 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:

[!code-csharp]

The following code creates two CORS policies:

[!code-csharp]

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":

[!code-csharp]

The following code disables CORS for the GetValues2 action:

[!code-csharp]

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

xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsOptions.AddPolicy%2A is called in Program.cs. For some options, it may be helpful to read the How CORS works section first.

Set the allowed origins

xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.AllowAnyOrigin%2A: 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.

[!NOTE]
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.

xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.SetIsOriginAllowedToAllowWildcardSubdomains%2A: Sets the xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicy.IsOriginAllowed%2A property of the policy to be a function that allows origins to match a configured wildcard domain when evaluating if the origin is allowed.

[!code-csharp]

Set the allowed HTTP methods

xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.AllowAnyMethod%2A:

  • 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 xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.WithHeaders%2A and specify the allowed headers:

[!code-csharp]

To allow all author request headers, call xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.AllowAnyHeader%2A:

[!code-csharp]

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 xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.WithExposedHeaders%2A:

[!code-csharp]

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 xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.AllowCredentials%2A:

[!code-csharp]

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.

The CORS specification also states that setting origins to "*" (all origins) is invalid if the Access-Control-Allow-Credentials header is present.

Preflight requests

For some CORS requests, the browser sends an additional OPTIONS request before making the actual request. This request is called a preflight request. The browser can skip the preflight request if all the following conditions are true:

  • The request method is GET, HEAD, or POST.
  • The app doesn’t set request headers other than Accept, Accept-Language, Content-Language, Content-Type, or Last-Event-ID.
  • The Content-Type header, if set, has one of the following values:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

The rule on request headers set for the client request applies to headers that the app sets by calling setRequestHeader on the XMLHttpRequest object. The CORS specification calls these headers author request headers. The rule doesn’t apply to headers the browser can set, such as User-Agent, Host, or Content-Length.

The following is an example response similar to the preflight request made from the [Put test] button in the Test CORS section of this document.

General:
Request URL: https://cors3.azurewebsites.net/api/values/5
Request Method: OPTIONS
Status Code: 204 No Content

Response Headers:
Access-Control-Allow-Methods: PUT,DELETE,GET
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f8...8;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Vary: Origin

Request Headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Method: PUT
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0

The preflight request uses the HTTP OPTIONS method. It may include the following headers:

  • Access-Control-Request-Method: The HTTP method that will be used for the actual request.
  • Access-Control-Request-Headers: A list of request headers that the app sets on the actual request. As stated earlier, this doesn’t include headers that the browser sets, such as User-Agent.
  • Access-Control-Allow-Methods

If the preflight request is denied, the app returns a 200 OK response but doesn’t set the CORS headers. Therefore, the browser doesn’t attempt the cross-origin request. For an example of a denied preflight request, see the Test CORS section of this document.

Using the F12 tools, the console app shows an error similar to one of the following, depending on the browser:

  • Firefox: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Reason: CORS request did not succeed). Learn More
  • Chromium based: Access to fetch at ‘https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5’ from origin ‘https://cors3.azurewebsites.net’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.

To allow specific headers, call xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.WithHeaders%2A:

[!code-csharp]

To allow all author request headers, call xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.AllowAnyHeader%2A:

[!code-csharp]

Browsers aren’t consistent in how they set Access-Control-Request-Headers. If either:

  • Headers are set to anything other than "*"
  • xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicy.AllowAnyHeader%2A is called:
    Include at least Accept, Content-Type, and Origin, plus any custom headers that you want to support.

Automatic preflight request code

When the CORS policy is applied either:

  • Globally by calling app.UseCors in Program.cs.
  • Using the [EnableCors] attribute.

ASP.NET Core responds to the preflight OPTIONS request.

Enabling CORS on a per-endpoint basis using RequireCors currently does not support automatic preflight requests.

The Test CORS section of this document demonstrates this behavior.

[HttpOptions] attribute for preflight requests

When CORS is enabled with the appropriate policy, ASP.NET Core generally responds to CORS preflight requests automatically. In some scenarios, this may not be the case. For example, using CORS with endpoint routing.

The following code uses the [HttpOptions] attribute to create endpoints for OPTIONS requests:

[!code-csharp]

See Test CORS with endpoint routing and [HttpOptions] for instructions on testing the preceding code.

Set the preflight expiration time

The Access-Control-Max-Age header specifies how long the response to the preflight request can be cached. To set this header, call xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.SetPreflightMaxAge%2A:

[!code-csharp]

How CORS works

This section describes what happens in a CORS request at the level of the HTTP messages.

  • CORS is not a security feature. CORS is a W3C standard that allows a server to relax the same-origin policy.
    • For example, a malicious actor could use Cross-Site Scripting (XSS) against your site and execute a cross-site request to their CORS enabled site to steal information.
  • An API isn’t safer by allowing CORS.
    • It’s up to the client (browser) to enforce CORS. The server executes the request and returns the response, it’s the client that returns an error and blocks the response. For example, any of the following tools will display the server response:
      • Fiddler
      • Postman
      • .NET HttpClient
      • A web browser by entering the URL in the address bar.
  • It’s a way for a server to allow browsers to execute a cross-origin XHR or Fetch API request that otherwise would be forbidden.
    • Browsers without CORS can’t do cross-origin requests. Before CORS, JSONP was used to circumvent this restriction. JSONP doesn’t use XHR, it uses the <script> tag to receive the response. Scripts are allowed to be loaded cross-origin.

The CORS specification introduced several new HTTP headers that enable cross-origin requests. If a browser supports CORS, it sets these headers automatically for cross-origin requests. Custom JavaScript code isn’t required to enable CORS.

The PUT test button on the deployed sample

The following is an example of a cross-origin request from the Values test button to https://cors1.azurewebsites.net/api/values. The Origin header:

  • Provides the domain of the site that’s making the request.
  • Is required and must be different from the host.

General headers

Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK

Response headers

Content-Encoding: gzip
Content-Type: text/plain; charset=utf-8
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Powered-By: ASP.NET

Request headers

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: cors1.azurewebsites.net
Origin: https://cors3.azurewebsites.net
Referer: https://cors3.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 ...

In OPTIONS requests, the server sets the Response headers Access-Control-Allow-Origin: {allowed origin} header in the response. For example, the deployed sample, Delete [EnableCors] button OPTIONS request contains the following headers:

General headers

Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content

Response headers

Access-Control-Allow-Headers: Content-Type,x-custom-header
Access-Control-Allow-Methods: PUT,DELETE,GET,OPTIONS
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors3.azurewebsites.net
Vary: Origin
X-Powered-By: ASP.NET

Request headers

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: DELETE
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/test?number=2
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0

In the preceding Response headers, the server sets the Access-Control-Allow-Origin header in the response. The https://cors1.azurewebsites.net value of this header matches the Origin header from the request.

If xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.AllowAnyOrigin%2A is called, the Access-Control-Allow-Origin: *, the wildcard value, is returned. AllowAnyOrigin allows any origin.

If the response doesn’t include the Access-Control-Allow-Origin header, the cross-origin request fails. Specifically, the browser disallows the request. Even if the server returns a successful response, the browser doesn’t make the response available to the client app.

HTTP redirection to HTTPS causes ERR_INVALID_REDIRECT on the CORS preflight request

Requests to an endpoint using HTTP that are redirected to HTTPS by xref:Microsoft.AspNetCore.Builder.HttpsPolicyBuilderExtensions.UseHttpsRedirection%2A fail with ERR_INVALID_REDIRECT on the CORS preflight request.

API projects can reject HTTP requests rather than use UseHttpsRedirection to redirect requests to HTTPS.

Display OPTIONS requests

By default, the Chrome and Edge browsers don’t show OPTIONS requests on the network tab of the F12 tools. To display OPTIONS requests in these browsers:

  • chrome://flags/#out-of-blink-cors or edge://flags/#out-of-blink-cors
  • disable the flag.
  • restart.

Firefox shows OPTIONS requests by default.

CORS in IIS

When deploying to IIS, CORS has to run before Windows Authentication if the server isn’t configured to allow anonymous access. To support this scenario, the IIS CORS module
needs to be installed and configured for the app.

Test CORS

The sample download has code to test CORS. See how to download. The sample is an API project with Razor Pages added:

[!code-csharp]

[!WARNING]
WithOrigins("https://localhost:<port>"); should only be used for testing a sample app similar to the download sample code.

The following ValuesController provides the endpoints for testing:

[!code-csharp]

MyDisplayRouteInfo is provided by the Rick.Docs.Samples.RouteInfo NuGet package and displays route information.

Test the preceding sample code by using one of the following approaches:

  • Use the deployed sample app at https://cors3.azurewebsites.net/. There is no need to download the sample.
  • Run the sample with dotnet run using the default URL of https://localhost:5001.
  • Run the sample from Visual Studio with the port set to 44398 for a URL of https://localhost:44398.

Using a browser with the F12 tools:

  • Select the Values button and review the headers in the Network tab.

  • Select the PUT test button. See Display OPTIONS requests for instructions on displaying the OPTIONS request. The PUT test creates two requests, an OPTIONS preflight request and the PUT request.

  • Select the GetValues2 [DisableCors] button to trigger a failed CORS request. As mentioned in the document, the response returns 200 success, but the CORS request is not made. Select the Console tab to see the CORS error. Depending on the browser, an error similar to the following is displayed:

    Access to fetch at 'https://cors1.azurewebsites.net/api/values/GetValues2' from origin 'https://cors3.azurewebsites.net' has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.

CORS-enabled endpoints can be tested with a tool, such as curl, Fiddler, or Postman. When using a tool, the origin of the request specified by the Origin header must differ from the host receiving the request. If the request isn’t cross-origin based on the value of the Origin header:

  • There’s no need for CORS Middleware to process the request.
  • CORS headers aren’t returned in the response.

The following command uses curl to issue an OPTIONS request with information:

curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i

Test CORS with endpoint routing and [HttpOptions]

Enabling CORS on a per-endpoint basis using RequireCors currently does not support automatic preflight requests. Consider the following code which uses endpoint routing to enable CORS:

[!code-csharp]

The following TodoItems1Controller provides endpoints for testing:

[!code-csharp]

Test the preceding code from the test page of the deployed sample.

The Delete [EnableCors] and GET [EnableCors] buttons succeed, because the endpoints have [EnableCors] and respond to preflight requests. The other endpoints fails. The GET button fails, because the JavaScript sends:

 headers: {
      "Content-Type": "x-custom-header"
 },

The following TodoItems2Controller provides similar endpoints, but includes explicit code to respond to OPTIONS requests:

[!code-csharp]

Test the preceding code from the test page of the deployed sample. In the Controller drop down list, select Preflight and then Set Controller. All the CORS calls to the TodoItems2Controller endpoints succeed.

Additional resources

  • Cross-Origin Resource Sharing (CORS)
  • Getting started with the IIS CORS module

:::moniker-end

:::moniker range=»< aspnetcore-6.0″

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]
xref:Microsoft.AspNetCore.Builder.CorsMiddlewareExtensions.UseCors%2A must be called in the correct order. For more information, see Middleware order. For example, UseCors must be called before xref:Microsoft.AspNetCore.Builder.ResponseCachingExtensions.UseResponseCaching%2A 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:

[!code-csharp]

The preceding code:

  • Sets the policy name to _myAllowSpecificOrigins. The policy name is arbitrary.
  • Calls the xref:Microsoft.AspNetCore.Builder.CorsMiddlewareExtensions.UseCors%2A 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 xref:Microsoft.Extensions.DependencyInjection.CorsServiceCollectionExtensions.AddCors%2A with a lambda expression. The lambda takes a xref:Microsoft.AspNetCore.Cors.Infrastructure.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 xref:Microsoft.AspNetCore.Builder.CorsMiddlewareExtensions.UseCors%2A before xref:Microsoft.AspNetCore.Builder.ResponseCachingExtensions.UseResponseCaching%2A.

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 xref:Microsoft.Extensions.DependencyInjection.MvcCorsMvcCoreBuilderExtensions.AddCors%2A method call adds CORS services to the app’s service container:

[!code-csharp]

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

The xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder methods can be chained, as shown in the following code:

[!code-csharp]

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

CORS with default policy and middleware

The following highlighted code enables the default CORS policy:

[!code-csharp]

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

Enable Cors with endpoint routing

Enabling CORS on a per-endpoint basis using RequireCors does not support automatic preflight requests. For more information, see this GitHub issue and Test CORS with endpoint routing and [HttpOptions].

With endpoint routing, CORS can be enabled on a per-endpoint basis using the xref:Microsoft.AspNetCore.Builder.CorsEndpointConventionBuilderExtensions.RequireCors%2A set of extension methods:

[!code-csharp]

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.

See Test CORS with endpoint routing and [HttpOptions] 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:

[!code-csharp]

The following code creates two CORS policies:

[!code-csharp]

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":

[!code-csharp]

The following code disables CORS for the GetValues2 action:

[!code-csharp]

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

xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsOptions.AddPolicy%2A is called in Startup.ConfigureServices. For some options, it may be helpful to read the How CORS works section first.

Set the allowed origins

xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.AllowAnyOrigin%2A: 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.

[!NOTE]
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.

xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.SetIsOriginAllowedToAllowWildcardSubdomains%2A: Sets the xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicy.IsOriginAllowed%2A property of the policy to be a function that allows origins to match a configured wildcard domain when evaluating if the origin is allowed.

[!code-csharp]

Set the allowed HTTP methods

xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.AllowAnyMethod%2A:

  • 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 xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.WithHeaders%2A and specify the allowed headers:

[!code-csharp]

To allow all author request headers, call xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.AllowAnyHeader%2A:

[!code-csharp]

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:

[!code-csharp]

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 xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.WithExposedHeaders%2A:

[!code-csharp]

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 xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.AllowCredentials%2A:

[!code-csharp]

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.

The CORS specification also states that setting origins to "*" (all origins) is invalid if the Access-Control-Allow-Credentials header is present.

Preflight requests

For some CORS requests, the browser sends an additional OPTIONS request before making the actual request. This request is called a preflight request. The browser can skip the preflight request if all the following conditions are true:

  • The request method is GET, HEAD, or POST.
  • The app doesn’t set request headers other than Accept, Accept-Language, Content-Language, Content-Type, or Last-Event-ID.
  • The Content-Type header, if set, has one of the following values:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

The rule on request headers set for the client request applies to headers that the app sets by calling setRequestHeader on the XMLHttpRequest object. The CORS specification calls these headers author request headers. The rule doesn’t apply to headers the browser can set, such as User-Agent, Host, or Content-Length.

The following is an example response similar to the preflight request made from the [Put test] button in the Test CORS section of this document.

General:
Request URL: https://cors3.azurewebsites.net/api/values/5
Request Method: OPTIONS
Status Code: 204 No Content

Response Headers:
Access-Control-Allow-Methods: PUT,DELETE,GET
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f8...8;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Vary: Origin

Request Headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Method: PUT
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0

The preflight request uses the HTTP OPTIONS method. It may include the following headers:

  • Access-Control-Request-Method: The HTTP method that will be used for the actual request.
  • Access-Control-Request-Headers: A list of request headers that the app sets on the actual request. As stated earlier, this doesn’t include headers that the browser sets, such as User-Agent.
  • Access-Control-Allow-Methods

If the preflight request is denied, the app returns a 200 OK response but doesn’t set the CORS headers. Therefore, the browser doesn’t attempt the cross-origin request. For an example of a denied preflight request, see the Test CORS section of this document.

Using the F12 tools, the console app shows an error similar to one of the following, depending on the browser:

  • Firefox: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5. (Reason: CORS request did not succeed). Learn More
  • Chromium based: Access to fetch at ‘https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5’ from origin ‘https://cors3.azurewebsites.net’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.

To allow specific headers, call xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.WithHeaders%2A:

[!code-csharp]

To allow all author request headers, call xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.AllowAnyHeader%2A:

[!code-csharp]

Browsers aren’t consistent in how they set Access-Control-Request-Headers. If either:

  • Headers are set to anything other than "*"
  • xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicy.AllowAnyHeader%2A is called:
    Include at least Accept, Content-Type, and Origin, plus any custom headers that you want to support.

Automatic preflight request code

When the CORS policy is applied either:

  • Globally by calling app.UseCors in Startup.Configure.
  • Using the [EnableCors] attribute.

ASP.NET Core responds to the preflight OPTIONS request.

Enabling CORS on a per-endpoint basis using RequireCors currently does not support automatic preflight requests.

The Test CORS section of this document demonstrates this behavior.

[HttpOptions] attribute for preflight requests

When CORS is enabled with the appropriate policy, ASP.NET Core generally responds to CORS preflight requests automatically. In some scenarios, this may not be the case. For example, using CORS with endpoint routing.

The following code uses the [HttpOptions] attribute to create endpoints for OPTIONS requests:

[!code-csharp]

See Test CORS with endpoint routing and [HttpOptions] for instructions on testing the preceding code.

Set the preflight expiration time

The Access-Control-Max-Age header specifies how long the response to the preflight request can be cached. To set this header, call xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.SetPreflightMaxAge%2A:

[!code-csharp]

How CORS works

This section describes what happens in a CORS request at the level of the HTTP messages.

  • CORS is not a security feature. CORS is a W3C standard that allows a server to relax the same-origin policy.
    • For example, a malicious actor could use Cross-Site Scripting (XSS) against your site and execute a cross-site request to their CORS enabled site to steal information.
  • An API isn’t safer by allowing CORS.
    • It’s up to the client (browser) to enforce CORS. The server executes the request and returns the response, it’s the client that returns an error and blocks the response. For example, any of the following tools will display the server response:
      • Fiddler
      • Postman
      • .NET HttpClient
      • A web browser by entering the URL in the address bar.
  • It’s a way for a server to allow browsers to execute a cross-origin XHR or Fetch API request that otherwise would be forbidden.
    • Browsers without CORS can’t do cross-origin requests. Before CORS, JSONP was used to circumvent this restriction. JSONP doesn’t use XHR, it uses the <script> tag to receive the response. Scripts are allowed to be loaded cross-origin.

The CORS specification introduced several new HTTP headers that enable cross-origin requests. If a browser supports CORS, it sets these headers automatically for cross-origin requests. Custom JavaScript code isn’t required to enable CORS.

The PUT test button on the deployed sample

The following is an example of a cross-origin request from the Values test button to https://cors1.azurewebsites.net/api/values. The Origin header:

  • Provides the domain of the site that’s making the request.
  • Is required and must be different from the host.

General headers

Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK

Response headers

Content-Encoding: gzip
Content-Type: text/plain; charset=utf-8
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Powered-By: ASP.NET

Request headers

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: cors1.azurewebsites.net
Origin: https://cors3.azurewebsites.net
Referer: https://cors3.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 ...

In OPTIONS requests, the server sets the Response headers Access-Control-Allow-Origin: {allowed origin} header in the response. For example, the deployed sample, Delete [EnableCors] button OPTIONS request contains the following headers:

General headers

Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content

Response headers

Access-Control-Allow-Headers: Content-Type,x-custom-header
Access-Control-Allow-Methods: PUT,DELETE,GET,OPTIONS
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors3.azurewebsites.net
Vary: Origin
X-Powered-By: ASP.NET

Request headers

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: DELETE
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/test?number=2
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0

In the preceding Response headers, the server sets the Access-Control-Allow-Origin header in the response. The https://cors1.azurewebsites.net value of this header matches the Origin header from the request.

If xref:Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder.AllowAnyOrigin%2A is called, the Access-Control-Allow-Origin: *, the wildcard value, is returned. AllowAnyOrigin allows any origin.

If the response doesn’t include the Access-Control-Allow-Origin header, the cross-origin request fails. Specifically, the browser disallows the request. Even if the server returns a successful response, the browser doesn’t make the response available to the client app.

Display OPTIONS requests

By default, the Chrome and Edge browsers don’t show OPTIONS requests on the network tab of the F12 tools. To display OPTIONS requests in these browsers:

  • chrome://flags/#out-of-blink-cors or edge://flags/#out-of-blink-cors
  • disable the flag.
  • restart.

Firefox shows OPTIONS requests by default.

CORS in IIS

When deploying to IIS, CORS has to run before Windows Authentication if the server isn’t configured to allow anonymous access. To support this scenario, the IIS CORS module
needs to be installed and configured for the app.

Test CORS

The sample download has code to test CORS. See how to download. The sample is an API project with Razor Pages added:

[!code-csharp]

[!WARNING]
WithOrigins("https://localhost:<port>"); should only be used for testing a sample app similar to the download sample code.

The following ValuesController provides the endpoints for testing:

[!code-csharp]

MyDisplayRouteInfo is provided by the Rick.Docs.Samples.RouteInfo NuGet package and displays route information.

Test the preceding sample code by using one of the following approaches:

  • Use the deployed sample app at https://cors3.azurewebsites.net/. There is no need to download the sample.
  • Run the sample with dotnet run using the default URL of https://localhost:5001.
  • Run the sample from Visual Studio with the port set to 44398 for a URL of https://localhost:44398.

Using a browser with the F12 tools:

  • Select the Values button and review the headers in the Network tab.

  • Select the PUT test button. See Display OPTIONS requests for instructions on displaying the OPTIONS request. The PUT test creates two requests, an OPTIONS preflight request and the PUT request.

  • Select the GetValues2 [DisableCors] button to trigger a failed CORS request. As mentioned in the document, the response returns 200 success, but the CORS request is not made. Select the Console tab to see the CORS error. Depending on the browser, an error similar to the following is displayed:

    Access to fetch at 'https://cors1.azurewebsites.net/api/values/GetValues2' from origin 'https://cors3.azurewebsites.net' has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.

CORS-enabled endpoints can be tested with a tool, such as curl, Fiddler, or Postman. When using a tool, the origin of the request specified by the Origin header must differ from the host receiving the request. If the request isn’t cross-origin based on the value of the Origin header:

  • There’s no need for CORS Middleware to process the request.
  • CORS headers aren’t returned in the response.

The following command uses curl to issue an OPTIONS request with information:

curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i

Test CORS with endpoint routing and [HttpOptions]

Enabling CORS on a per-endpoint basis using RequireCors currently does not support automatic preflight requests. Consider the following code which uses endpoint routing to enable CORS:

[!code-csharp]

The following TodoItems1Controller provides endpoints for testing:

[!code-csharp]

Test the preceding code from the test page of the deployed sample.

The Delete [EnableCors] and GET [EnableCors] buttons succeed, because the endpoints have [EnableCors] and respond to preflight requests. The other endpoints fails. The GET button fails, because the JavaScript sends:

 headers: {
      "Content-Type": "x-custom-header"
 },

The following TodoItems2Controller provides similar endpoints, but includes explicit code to respond to OPTIONS requests:

[!code-csharp]

Test the preceding code from the test page of the deployed sample. In the Controller drop down list, select Preflight and then Set Controller. All the CORS calls to the TodoItems2Controller endpoints succeed.

Additional resources

  • Cross-Origin Resource Sharing (CORS)
  • Getting started with the IIS CORS module

:::moniker-end

Interconnected

Last night I was working on updating my ASP.NET Core AlbumViewer sample application to Angular 2.0 and in the process ran into CORS problems. Angular 2.0’s default working environment runs a development server off a seperate port which is effectively a seperate domain and all calls back to the main ASP.NET site for the API calls effectively are cross domain calls. Alas those calls failed and upon closer inspection it was due to the fact that the CORS headers weren’t getting sent.

CORS Setup in ASP.NET Core

CORS is a server based mechanism that essentially lets a server say:

I allow cross domain calls from the domains I specify

It’s good to be king, huh? (especially a king with no clothes since the protocol does next to nothing to prevent malicious attacks but that’s a story for another post)

When browsers make cross domain calls using XHR, they request CORS headers to decide whether the target server allows access to the source domain. In this case the source domain is Angular’s dev server (localhost:3000) and the target server is my ASP.NET API service (localhost:5000 (raw Kestrel) or localhost/albumviewer (IIS/IIS Express)).

To set up CORS is at least a 3 step process:

  • You register CORS functionality
  • You configure CORS options
  • You apply the functionality

There are a number of different ways to do this but by far the best approach IMHO is to create a CORS policy and then apply that policy either globally to all requests or specific controllers.

I like the policy approach because:

  • It allows me to add CORS and declare the policy in one place
  • It allows the policy to be reused and be applied selectively

Below I use the explicit policy approach.

Register and Define a Policy

To do this start with registering CORS functionality in ConfigureServices() of Startup.cs:

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

The AddCors() call above adds the CORS features to ASP.NET and creates a custom policy that can be reused in the application by name. There are other ways to do essentially the same thing by explicitly adding a policy builder in the configuration step but to me this seems cleanest — define one or more policies up front and then apply it.

Apply the Policy

Once the policy has been defined it can be applied.

You can apply the policy globally to every request in the application by call app.useCors() in the Configure() method of Startup:

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

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

    // ...
    
    // IMPORTANT: Make sure UseCors() is called BEFORE this
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

UseCors() has to be called before UseMvc()

Make sure you declare the CORS functionality before MVC so the middleware fires before the MVC pipeline gets control and terminates the request.

or you can apply the policy to individual controllers:

[EnableCors("CorsPolicy")]
[ApiExceptionFilter]
public class AlbumViewerApiController : Controller

Check that it works

When it’s all said and done you now should get the appropriate CORS headers with your response:

HTTP/1.1 200 OK
Date: Tue, 27 Sep 2016 07:09:08 GMT
Content-Type: application/json; charset=utf-8
Server: Kestrel
Vary: Origin
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost:3000
Content-Length: 2851

Note that the actual headers sent may vary depending on what your request needs. GET operations might have different CORS headers than a POST or OPTION request.

Watch out for testing CORS without Cross Domain!

So last night I reviewed my code and checked for the CORS functionality. It turns out I had at some point renamed the policy and so the policy strings were out of sync resulting in mismatched policy names and no CORS headers. Once I fixed that it seemed that everything should be well.

I went ahead and tested API calls through a browser and found: No CORS headers. Checked all again for errors and it all looked just fine. WTH? It wasn’t until I tried running the full Angular application again that I found that the app was now working, and the CORS headers were being sent properly. In this duh! moment I realized of course that this is the correct behavior.

CORS headers are only sent on cross domain requests and the ASP.NET CORS module is smart enough to detect whether a same domain request is firing and if it is, doesn’t send the headers. Duh — of course, but in the heat of the moment I totally didn’t think of that.

The sad thing is this is not the first time I’ve made this mistake :-) As soon as I figured it out, I realized I had made that very same mistake a few months earlier when I set up the original CORS functionality and tested — and failed/flailed. History repeats itself. To avoid that — I’m writing it down to jog my memory.

So, if you’re going to test CORS operation the only effective way to do is is by using a cross-site origin to trigger the CORS behavior. Either use a cross site client app (my Angular app in this case) or an HTTP test client (I used my West Wind WebSurge tool with an explicit origin header) and avoid scratching your head on why the CORS headers are not showing up.

Resources

  • Official ASP.NET CORS documentation
  • Remove From My Forums
  • Question

  • User2142955891 posted

    CORS does not work as expected using aspnet core 2.2 web api project.

    I have taken the code from cors documentation.

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

    Lets start with a GET request. My client url is http://localhost:8080.

    builder.WithOrigins(«http://localhost:8080«); This works.

    builder.WithOrigins(«http://localhost:8081«); This causes cors error which is correct

    builder.WithOrigins(«http://localhost:8080»).WithMethods(«POST»); This allows GET requests through when it shouldn’t. builder.WithOrigins(«http://localhost:8080»).WithMethods(«POST»);This STOPS POST requests through when
    it shouldn’t.

    I have also used ALL the allow methods and my POSTs wont work. The GETs always work. The cors error is being thrown when the OPTIONS request is sent.

    How can I fix this issue?

Enable CORS ASPNET Core 30

In this article, we shall see how to enable CORS in ASP.NET Core API in a few simple easy steps. We already covered a few basics of CORS (Cross-origin resource sharing) in our last article.

We shall cover the below aspects in today’s article,

  • Getting started
  • Understanding CORS
  • Let’s see a simple ASP.NET Core example
  • Step 1 – Enabling CORS using CorsPolicyBuilder
  • Step 2 – Enable CORS Middleware
  • Order of Middleware Execution for CORS
  • Global CORS with endpoint routing
  • CORS for Specific endpoints
  • Summary

Getting started

Understanding CORS

Add CORS in NET Core Best Practices

By design Web application executes a cross-origin HTTP request when it requests a resource that has a different origin or domain. This is due to security reasons and as per design specifications.

For example, Applications origin could be different due to differences in below,

  • Domain,
  • Protocol
  • Port

With CORS policy cross-origin requests and data transfers between browsers and servers can be secured.

If the Client (Thin) needs to communicate CORS is the only way where a server will allow to run Cross-Origin requests.

Let’s see a simple ASP.NET Core example

Create a sample service from the template of your choice. Here in this sample, I have used the .NET Core 3.1 project template.

If CORS is not enabled on the service side then, you shall get below similar familiar error while invoking API from different domains like any UI (Angular) or ASP.NET Web Application.

Access to fetch at ‘http://localhost:57827/api/test’ from origin ‘http://localhost:57838’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.

Below are basic steps to enable CORS in the API pipeline.

Step 1 – Enabling CORS using CorsPolicyBuilder

Add cross-origin resource sharing to the service collection using the ConfigServices() method.

Please update the ConfigureService() method as below,

 

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

            services.AddControllers();
        }

The service.AddCors() method adds cross-origin resource sharing to the service collection for the given policy defined. This method makes use of CorsPolicyBuilder to define the correct policy to be defined in the app’s container.

CorsPolicyBuilder class exposes multiple methods to help you define the rule based on headers or origin or credentials etc.

  • AllowAnyHeader() – The policy allows any header.
  • AllowAnyMethod() – The policy allows any method.
  • AllowAnyOrigin() – The policy allows any origin.
  • AllowCredentials() – Sets the policy to allow credentials.
  • WithHeaders ()- Adds the specified headers to the policy.
  • WithMethods() – Adds the specified methods to the policy.
  • WithOrigins() – Adds the specified origins to the policy.

To protect your service from CSRF (cross-site request forgery), it’s recommended not to use methods like AllowAnyOrigin or AllowAnyHeader. Such configurations are vulnerable in nature.

So one can define the same with origin as below,

services.AddCors(options => options.AddPolicy("TheCodeBuzzPolicy", builder =>
            {
                builder.WithOrigins("https://TheCodeBuzzTest.com")
                       .AllowAnyMethod()
                       .AllowAnyHeader();
            }));

Note: The URL should not contain a Trailing slash (/)

Step 2 – Enable CORS Middleware

Update Configure() method as below for enabling the CORS Middleware

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

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseCors("MyPolicy");

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
            
        }


Order of Middleware Execution for CORS

Order of CORS middleware execution is important in the API pipeline. UserCors method should be called after the UseRouting() and before UseEndpoint(..) method.

Enable CORS in ASPNET Core30

The above code also ensures CORS policies are applied to all the app endpoints using CORS.

Global CORS with endpoint routing

One can use the Global CORS for all the endpoints of any Controller in API or Service. So here you define CORS globally which gets applied to all API endpoints of all Controllers exposed endpoints.

app.UseEndpoints(endpoints =>
            {  endpoints.MapControllers().RequireCors("TheCodeBuzzPolicy");

            });

CORS for Specific endpoints

One can use the enable CORS for the specific endpoints of any Controller in API or Service. So here you define CORS for one or more APIs using simple annotation techniques.

One can use the [EnableCors] attribute as an alternative to GLOBAL CORS settings. This will let you define CORS for specific endpoints using an attribute-driven approach.

Here is an example for adding a CORS policy for the POST method,

        

        [EnableCors("TheCodeBuzzPolicy")]
        [HttpPost]
        public void Post([FromBody] string value)
        {
        }

That’s all. This was very much the basics about CORS, what we learned today.

Do you have any comments or ideas or any better suggestions to share?

Please sound off your comments below.

Happy Coding !!

Happy Coding!!

References:

  • Angular – JWT Authentication using HTTPClient Examples
  • Create HTTPClient using IHttpClientFactory in ASP.NET Core

Summary

Today in this article we learned the basic steps required to enable cross-domain resource sharing in ASP.NET Core API. We also learned how to enable CORS in the newest .NET Core framework with a Basic understanding of CORS. We also looked at Global and Local (API-specific) CORS configuration.


Please bookmark this page and share it with your friends. Please Subscribe to the blog to get a notification on freshly published best practices and guidelines for software design and development.


Понравилась статья? Поделить с друзьями:
  • Asp net application error
  • Asp net 1309 ошибка
  • Asp mvc error 500
  • Asmmap64 sys как исправить ошибку
  • Asmb8 ikvm java error