[asp.net] Access-control-allow-origin with multiple domains

In my web.config I would like to specify more than one domain for the access-control-allow-origin directive. I don't want to use *. I've tried this syntax:

<add name="Access-Control-Allow-Origin" value="http://localhost:1506, http://localhost:1502" />

this one

<add name="Access-Control-Allow-Origin" value="http://localhost:1506 http://localhost:1502" />

this one

<add name="Access-Control-Allow-Origin" value="http://localhost:1506; http://localhost:1502" />

and this one

<add name="Access-Control-Allow-Origin" value="http://localhost:1506" />
<add name="Access-Control-Allow-Origin" value="http://localhost:1502" />

but none of them work. What is the correct syntax ?

This question is related to asp.net iis cors web-config

The answer is


You only need:

  • add a Global.asax to your project,
  • delete <add name="Access-Control-Allow-Origin" value="*" /> from your web.config.
  • afterward, add this in the Application_BeginRequest method of Global.asax:

    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin","*");
    
    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
    {
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept");
        HttpContext.Current.Response.End();
    }
    

I hope this help. that work for me.


For IIS 7.5+ and Rewrite 2.0 you can use:

<system.webServer>
   <httpProtocol>
     <customHeaders>
         <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
         <add name="Access-Control-Allow-Methods" value="POST,GET,OPTIONS,PUT,DELETE" />
     </customHeaders>
   </httpProtocol>
        <rewrite>            
            <outboundRules>
                <clear />                
                <rule name="AddCrossDomainHeader">
                    <match serverVariable="RESPONSE_Access_Control_Allow_Origin" pattern=".*" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="true">
                        <add input="{HTTP_ORIGIN}" pattern="(http(s)?://((.+\.)?domain1\.com|(.+\.)?domain2\.com|(.+\.)?domain3\.com))" />
                    </conditions>
                    <action type="Rewrite" value="{C:0}" />
                </rule>           
            </outboundRules>
        </rewrite>
 </system.webServer>

Explaining the server variable RESPONSE_Access_Control_Allow_Origin portion:
In Rewrite you can use any string after RESPONSE_ and it will create the Response Header using the rest of the word as the header name (in this case Access-Control-Allow-Origin). Rewrite uses underscores "_" instead of dashes "-" (rewrite converts them to dashes)

Explaining the server variable HTTP_ORIGIN :
Similarly, in Rewrite you can grab any Request Header using HTTP_ as the prefix. Same rules with the dashes (use underscores "_" instead of dashes "-").


After reading every answer and trying them, none of them helped me. What I found while searching elsewhere is that you can create a custom attribute that you can then add to your controller. It overwrites the EnableCors ones and add the whitelisted domains in it.

This solution is working well because it lets you have the whitelisted domains in the webconfig (appsettings) instead of harcoding them in the EnableCors attribute on your controller.

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class EnableCorsByAppSettingAttribute : Attribute, ICorsPolicyProvider
{
    const string defaultKey = "whiteListDomainCors";
    private readonly string rawOrigins;
    private CorsPolicy corsPolicy;

    /// <summary>
    /// By default uses "cors:AllowedOrigins" AppSetting key
    /// </summary>
    public EnableCorsByAppSettingAttribute()
        : this(defaultKey) // Use default AppSetting key
    {
    }

    /// <summary>
    /// Enables Cross Origin
    /// </summary>
    /// <param name="appSettingKey">AppSetting key that defines valid origins</param>
    public EnableCorsByAppSettingAttribute(string appSettingKey)
    {
        // Collect comma separated origins
        this.rawOrigins = AppSettings.whiteListDomainCors;
        this.BuildCorsPolicy();
    }

    /// <summary>
    /// Build Cors policy
    /// </summary>
    private void BuildCorsPolicy()
    {
        bool allowAnyHeader = String.IsNullOrEmpty(this.Headers) || this.Headers == "*";
        bool allowAnyMethod = String.IsNullOrEmpty(this.Methods) || this.Methods == "*";

        this.corsPolicy = new CorsPolicy
        {
            AllowAnyHeader = allowAnyHeader,
            AllowAnyMethod = allowAnyMethod,
        };

        // Add origins from app setting value
        this.corsPolicy.Origins.AddCommaSeperatedValues(this.rawOrigins);
        this.corsPolicy.Headers.AddCommaSeperatedValues(this.Headers);
        this.corsPolicy.Methods.AddCommaSeperatedValues(this.Methods);
    }

    public string Headers { get; set; }
    public string Methods { get; set; }

    public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request,
                                               CancellationToken cancellationToken)
    {
        return Task.FromResult(this.corsPolicy);
    }
}

    internal static class CollectionExtensions
{
    public static void AddCommaSeperatedValues(this ICollection<string> current, string raw)
    {
        if (current == null)
        {
            return;
        }

        var paths = new List<string>(AppSettings.whiteListDomainCors.Split(new char[] { ',' }));
        foreach (var value in paths)
        {
            current.Add(value);
        }
    }
}

I found this guide online and it worked like a charm :

http://jnye.co/Posts/2032/dynamic-cors-origins-from-appsettings-using-web-api-2-2-cross-origin-support

I thought i'd drop that here for anyone in need.


I managed to solve this in the Request handling code following advice from 'monsur'.

string origin = WebOperationContext.Current.IncomingRequest.Headers.Get("Origin");

WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", origin);

Try this:

<add name="Access-Control-Allow-Origin" value="['URL1','URL2',...]" />


Look into the Thinktecture IdentityModel library -- it has full CORS support:

http://brockallen.com/2012/06/28/cors-support-in-webapi-mvc-and-iis-with-thinktecture-identitymodel/

And it can dynamically emit the ACA-Origin you want.


For IIS 7.5+ you can use IIS CORS Module: https://www.iis.net/downloads/microsoft/iis-cors-module

Your web.config should be something like this:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <cors enabled="true" failUnlistedOrigins="true">
            <add origin="http://localhost:1506">
                <allowMethods>                    
                    <add method="GET" />
                    <add method="HEAD" />
                    <add method="POST" />
                    <add method="PUT" /> 
                    <add method="DELETE" /> 
                </allowMethods>
            </add>
            <add origin="http://localhost:1502">
                <allowMethods>
                    <add method="GET" />
                    <add method="HEAD" />
                    <add method="POST" />
                    <add method="PUT" /> 
                    <add method="DELETE" /> 
                </allowMethods>
            </add>
        </cors>
    </system.webServer>
</configuration>

You can find the configuration reference in here: https://docs.microsoft.com/en-us/iis/extensions/cors-module/cors-module-configuration-reference


In Web.API this attribute can be added using Microsoft.AspNet.WebApi.Cors as detailed at http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api

In MVC you could create a filter attribute to do this work for you:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,
                AllowMultiple = true, Inherited = true)]
public class EnableCorsAttribute : FilterAttribute, IActionFilter {
    private const string IncomingOriginHeader = "Origin";
    private const string OutgoingOriginHeader = "Access-Control-Allow-Origin";
    private const string OutgoingMethodsHeader = "Access-Control-Allow-Methods";
    private const string OutgoingAgeHeader = "Access-Control-Max-Age";

    public void OnActionExecuted(ActionExecutedContext filterContext) {
        // Do nothing
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var isLocal = filterContext.HttpContext.Request.IsLocal;
        var originHeader = 
             filterContext.HttpContext.Request.Headers.Get(IncomingOriginHeader);
        var response = filterContext.HttpContext.Response;

        if (!String.IsNullOrWhiteSpace(originHeader) &&
            (isLocal || IsAllowedOrigin(originHeader))) {
            response.AddHeader(OutgoingOriginHeader, originHeader);
            response.AddHeader(OutgoingMethodsHeader, "GET,POST,OPTIONS");
            response.AddHeader(OutgoingAgeHeader, "3600");
        }
    }

    protected bool IsAllowedOrigin(string origin) {
        // ** replace with your own logic to check the origin header
        return true;
    }
}

Then either enable it for specific actions / controllers:

[EnableCors]
public class SecurityController : Controller {
    // *snip*
    [EnableCors]
    public ActionResult SignIn(Guid key, string email, string password) {

Or add it for all controllers in Global.asax.cs

protected void Application_Start() {
    // *Snip* any existing code

    // Register global filter
    GlobalFilters.Filters.Add(new EnableCorsAttribute());
    RegisterGlobalFilters(GlobalFilters.Filters);

    // *snip* existing code
}

You can add this code to your asp.net webapi project

in file Global.asax

    protected void Application_BeginRequest()
{
    string origin = Request.Headers.Get("Origin");
    if (Request.HttpMethod == "OPTIONS")
    {
        Response.AddHeader("Access-Control-Allow-Origin", origin);
        Response.AddHeader("Access-Control-Allow-Headers", "*");
        Response.AddHeader("Access-Control-Allow-Methods", "GET,POST,PUT,OPTIONS,DELETE");
        Response.StatusCode = 200;
        Response.End();
    }
    else
    {
        Response.AddHeader("Access-Control-Allow-Origin", origin);
        Response.AddHeader("Access-Control-Allow-Headers", "*");
        Response.AddHeader("Access-Control-Allow-Methods", "GET,POST,PUT,OPTIONS,DELETE");
    }
}

You can use owin middleware to define cors policy in which you can define multiple cors origins

return new CorsOptions
        {
            PolicyProvider = new CorsPolicyProvider
            {
                PolicyResolver = context =>
                {
                    var policy = new CorsPolicy()
                    {
                        AllowAnyOrigin = false,
                        AllowAnyMethod = true,
                        AllowAnyHeader = true,
                        SupportsCredentials = true
                    };
                    policy.Origins.Add("http://foo.com");
                    policy.Origins.Add("http://bar.com");
                    return Task.FromResult(policy);
                }
            }
        };

Examples related to asp.net

RegisterStartupScript from code behind not working when Update Panel is used You must add a reference to assembly 'netstandard, Version=2.0.0.0 No authenticationScheme was specified, and there was no DefaultChallengeScheme found with default authentification and custom authorization How to use log4net in Asp.net core 2.0 Visual Studio 2017 error: Unable to start program, An operation is not legal in the current state How to create roles in ASP.NET Core and assign them to users? How to handle Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause() ASP.NET Core Web API Authentication Could not load file or assembly 'CrystalDecisions.ReportAppServer.CommLayer, Version=13.0.2000.0 WebForms UnobtrusiveValidationMode requires a ScriptResourceMapping for jquery

Examples related to iis

ASP.NET Core 1.0 on IIS error 502.5 CS1617: Invalid option ‘6’ for /langversion; must be ISO-1, ISO-2, 3, 4, 5 or Default Publish to IIS, setting Environment Variable IIS Manager in Windows 10 The page cannot be displayed because an internal server error has occurred on server The service cannot accept control messages at this time NuGet: 'X' already has a dependency defined for 'Y' Changing project port number in Visual Studio 2013 System.Data.SqlClient.SqlException: Login failed for user "This operation requires IIS integrated pipeline mode."

Examples related to cors

Axios having CORS issue Cross-Origin Read Blocking (CORB) Jquery AJAX: No 'Access-Control-Allow-Origin' header is present on the requested resource How to allow CORS in react.js? Set cookies for cross origin requests XMLHttpRequest blocked by CORS Policy How to enable CORS in ASP.net Core WebAPI No 'Access-Control-Allow-Origin' header is present on the requested resource—when trying to get data from a REST API How to overcome the CORS issue in ReactJS Trying to use fetch and pass in mode: no-cors

Examples related to web-config

No assembly found containing an OwinStartupAttribute Error IIS Config Error - This configuration section cannot be used at this path How to enable GZIP compression in IIS 7.5 how to set start page in webconfig file in asp.net c# Authentication issue when debugging in VS2013 - iis express Forms authentication timeout vs sessionState timeout Specified argument was out of the range of valid values. Parameter name: site Access-control-allow-origin with multiple domains "An exception occurred while processing your request. Additionally, another exception occurred while executing the custom error page..." ASP.NET: HTTP Error 500.19 – Internal Server Error 0x8007000d