IIS CORS module Configuration Reference

by the IIS Team

This article provides an overview of the IIS CORS module and explains the configuration of the module.

Functionality Overview

The Microsoft IIS CORS Module is an extension that enables web sites to support the CORS(Cross-Origin Resource Sharing) protocol.

The IIS CORS module provides a way for web server administrators and web site authors to make their applications support the CORS protocol. With this module, developers can move CORS logic out of their applications and rely on the web server. The module's handling of CORS requests is determined by rules defined in the configuration. These CORS rules can be easily defined or configured making it simple to delegate all CORS protocol handling to the module.

IIS CORS module is a server-side CORS component

The CORS protocol governs client/server communication. Usually, web browsers act as the client-side CORS component, while the IIS server works as the server-side CORS component with the help of the IIS CORS module.

A CORS request occurs when a protocol aware client, such as a web browser, makes a request to a domain (origin) that differs from the current domain. This scenario is known as a cross-origin request. When CORS is not used, cross-origin requests will be blocked by the client. When the CORS module is used, IIS will inform clients whether a cross-origin request can be performed based on the IIS configuration.

CORS preflight request

A CORS preflight request is used to determine whether the resource being requested is set to be shared across origins by the server. The CORS preflight uses the HTTP OPTIONS method with the ACCESS-CONTROL-REQUEST-METHOD and the ORIGIN request headers. The IIS CORS module is designed to handle the CORS preflight requests before other IIS modules handle the same request. The OPTIONS requests are always anonymous, so CORS module provides IIS servers a way to correctly respond to the preflight request even if anonymous authentification needs to be disabled server-wise.

CORS Configuration

The IIS CORS is configured via a site or application web.config file and has its own cors configuration section within system.webServer.

Below are the configuration examples to enable CORS for a site named contentSite. The * origin allows all host origins; however, those that start with http://* are later excluded. For the https://*.microsoft.com host origin, the CORS response is customized with various CORS configurations as an example.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <cors enabled="true" failUnlistedOrigins="true">
            <add origin="*" />
            <add origin="https://*.microsoft.com"
                 allowCredentials="true"
                 maxAge="120"> 
                <allowHeaders allowAllRequestedHeaders="true">
                    <add header="header1" />
                    <add header="header2" />
                </allowHeaders>
                <allowMethods>
                     <add method="DELETE" />
                </allowMethods>
                <exposeHeaders>
                    <add header="header1" />
                    <add header="header2" />
                </exposeHeaders>
            </add>
            <add origin="http://*" allowed="false" />
        </cors>
    </system.webServer>
</configuration>

With the IIS CORS module, you can:

  1. Enable, disable CORS for a whole IIS server or for a specific IIS site, an application, a virtual directory, a physical directory or a file (system.webServer/cors).
  2. Configure all the origin host domains to be accepted with * origin host rule.
  3. Configure the list of specific origin host domains and allow only the CORS request which has the same value of the origin request header as one of listed origin host domains.
  4. Configure wild card origin host domains when configuring the list of origin domain such as http://* or https://*.mydomain.com.
  5. Configure a list of origin domains which should be disallowed as CORS request.
  6. Customize the CORS response header values with the configured values.

Attributes of the cors element

Attribute Description
enabled Optional Boolean attribute.
Specifies whether CORS is enabled.
The default value is false.
failUnlistedOrigins Optional Boolean attribute.
Specifies whether the CORS response status code to be set with 403 if the requested origin is not matched to the configured list of origin or if the origin host is configured to be disallowed.
The default value is false.

Adding Origin rule <add>

Origin rules

The <add> element of the <cors> collection specifies an individual origin to be added to the list of origin rules.

Attributes of the origin rule

Attribute Description
origin Required string attribute.
Specifies origin host on which to impose an origin rule. You can use an asterisk (*) to apply this rule to all origin request header values. You can also use an asterisk (*) as a wildcard for the child subdomain name. If there are multiple origin rules, it is applied to the most specific origin host name rule regardless of the allowed attribute value.
allowed Optional Boolean attribute.
Specifies whether to accept the CORS request for the origin host.
The default value is true.
allowCredentials Optional Boolean attribute.
Specifies whether to set the Access-Control-Allow-Credentials: true CORS response header. This attribute should be used only for a specific origin host name rather than * origin host for CORS protocol compliance.
The default value is false.
maxAge Optional integer attribute. Duration in seconds.
Specifies the value of the Access-Control-Max-Age response header for the preflight CORS request. The Access-Control-Max-Age response header is supposed to be set only for the CORS preflight requests. If you don't want to set the Access-Control-Max-Age header in the CORS response, set -1 for this attribute.
The default value is -1.

Using only * origin host rule

If there is only * origin host rule, IIS CORS module has some different behaviors compared to when there is a specific origin host name rule. If there is only * origin host rule, IIS CORS module does the following:

  1. The value of Access-Control-Allow-Origin response header is set to * regardless of the value of the origin request header sent by the client-side CORS component.
  2. Vary: origin response header is not added because IIS CORS does not generate Access-Control-Allow-Origin response header values other than * and there is no need to use the Vary: origin response header value.

Child Elements of the origin host rule

Element Description
allowHeaders configures allowHeaders collection that is used for the value of the Access-Control-Allow-Headers CORS response header for the origin host specified in the origin host rule.
The Access-Control-Allow-Headers response header will be set only for the actual CORS requests rather than the preflight requests.
allowMethods configures allowMethods collection that is used for the value of the Access-Control-Allow-Methods CORS response header for the origin host specified in the origin host rule.
The Access-Control-Allow-Methods response header will be set only for the CORS preflight requests.
exposeHeaders configures exposeHeaders collection that is used for the value of the Access-Control-Expose-Headers CORS response header for the origin host specified in the origin host rule.
The Access-Control-Expose-Headers response header will be set only for the actual CORS requests rather than the preflight requests.

Attributes of the allowHeaders element

Attribute Description
allowAllRequestedHeaders Optional Boolean attribute. If this is true, IIS module will take the value of the given Access-Control-Request-Headers CORS request header and set the Access-Control-Allow-Headers response header with the same value, which means all the given headers are allowed. If this is false, it sets the Access-Control-Allow-Headers response header with the header values of the allowHeaders collection, which means that only the listed headers are allowed. The default value is false.

Sample Code

C#

using System;
using System.Text;
using Microsoft.Web.Administration;

internal static class Sample {

    private static void Main() {

        using(ServerManager serverManager = new ServerManager()) {
            Configuration config = serverManager.GetWebConfiguration("contentSite");

            ConfigurationSection corsSection = config.GetSection("system.webServer/cors");
            corsSection["enabled"] = true;
            corsSection["failUnlistedOrigins"] = true;

            ConfigurationElementCollection corsCollection = corsSection.GetCollection();

            ConfigurationElement addElement = corsCollection.CreateElement("add");
            addElement["origin"] = @"*";
            corsCollection.Add(addElement);

            ConfigurationElement addElement1 = corsCollection.CreateElement("add");
            addElement1["origin"] = @"https://*.microsoft.com";
            addElement1["allowCredentials"] = true;
            addElement1["maxAge"] = 120;

            ConfigurationElement allowHeadersElement = addElement1.GetChildElement("allowHeaders");
            allowHeadersElement["allowAllRequestedHeaders"] = true;

            ConfigurationElementCollection allowHeadersCollection = allowHeadersElement.GetCollection();

            ConfigurationElement addElement2 = allowHeadersCollection.CreateElement("add");
            addElement2["header"] = @"header1";
            allowHeadersCollection.Add(addElement2);

            ConfigurationElement addElement3 = allowHeadersCollection.CreateElement("add");
            addElement3["header"] = @"header2";
            allowHeadersCollection.Add(addElement3);

            ConfigurationElementCollection allowMethodsCollection = addElement1.GetCollection("allowMethods");

            ConfigurationElement addElement4 = allowMethodsCollection.CreateElement("add");
            addElement4["method"] = @"DELETE";
            allowMethodsCollection.Add(addElement4);

            ConfigurationElementCollection exposeHeadersCollection = addElement1.GetCollection("exposeHeaders");

            ConfigurationElement addElement5 = exposeHeadersCollection.CreateElement("add");
            addElement5["header"] = @"header1";
            exposeHeadersCollection.Add(addElement5);

            ConfigurationElement addElement6 = exposeHeadersCollection.CreateElement("add");
            addElement6["header"] = @"header2";
            exposeHeadersCollection.Add(addElement6);
            corsCollection.Add(addElement1);

            ConfigurationElement addElement7 = corsCollection.CreateElement("add");
            addElement7["origin"] = @"http://*";
            addElement7["allowed"] = false;
            corsCollection.Add(addElement7);

            serverManager.CommitChanges();
        }
    }
}

JavaScript


var adminManager = new ActiveXObject('Microsoft.ApplicationHost.WritableAdminManager');
adminManager.CommitPath = "MACHINE/WEBROOT/APPHOST/contentSite";

var corsSection = adminManager.GetAdminSection("system.webServer/cors", "MACHINE/WEBROOT/APPHOST/contentSite");
corsSection.Properties.Item("enabled").Value = true;
corsSection.Properties.Item("failUnlistedOrigins").Value = true;

var corsCollection = corsSection.Collection;

var addElement = corsCollection.CreateNewElement("add");
addElement.Properties.Item("origin").Value = "*";
corsCollection.AddElement(addElement);


var addElement1 = corsCollection.CreateNewElement("add");
addElement1.Properties.Item("origin").Value = "https://*.microsoft.com";
addElement1.Properties.Item("allowCredentials").Value = true;
addElement1.Properties.Item("maxAge").Value = 120;
var allowHeadersElement = addElement1.ChildElements.Item("allowHeaders");
allowHeadersElement.Properties.Item("allowAllRequestedHeaders").Value = true;

var allowHeadersCollection = allowHeadersElement.Collection;

var addElement2 = allowHeadersCollection.CreateNewElement("add");
addElement2.Properties.Item("header").Value = "header1";
allowHeadersCollection.AddElement(addElement2);


var addElement3 = allowHeadersCollection.CreateNewElement("add");
addElement3.Properties.Item("header").Value = "header2";
allowHeadersCollection.AddElement(addElement3);


var allowMethodsCollection = addElement1.ChildElements.Item("allowMethods").Collection;

var addElement4 = allowMethodsCollection.CreateNewElement("add");
addElement4.Properties.Item("method").Value = "DELETE";
allowMethodsCollection.AddElement(addElement4);


var exposeHeadersCollection = addElement1.ChildElements.Item("exposeHeaders").Collection;

var addElement5 = exposeHeadersCollection.CreateNewElement("add");
addElement5.Properties.Item("header").Value = "header1";
exposeHeadersCollection.AddElement(addElement5);


var addElement6 = exposeHeadersCollection.CreateNewElement("add");
addElement6.Properties.Item("header").Value = "header2";
exposeHeadersCollection.AddElement(addElement6);

corsCollection.AddElement(addElement1);


var addElement7 = corsCollection.CreateNewElement("add");
addElement7.Properties.Item("origin").Value = "http://*";
addElement7.Properties.Item("allowed").Value = false;
corsCollection.AddElement(addElement7);


adminManager.CommitChanges();

Command Line (AppCmd)

appcmd.exe set config "contentSite" -section:system.webServer/cors /enabled:"True" /failUnlistedOrigins:"True"

appcmd.exe set config "contentSite" -section:system.webServer/cors /+"[origin='*']"

appcmd.exe set config "contentSite" -section:system.webServer/cors /+"[origin='https://*.microsoft.com',allowCredentials='True',maxAge='120']"
appcmd.exe set config "contentSite" -section:system.webServer/cors /[origin='https://*.microsoft.com',allowCredentials='True',maxAge='120'].allowHeaders.allowAllRequestedHeaders:"True"

appcmd.exe set config "contentSite" -section:system.webServer/cors /+"[origin='https://*.microsoft.com',allowCredentials='True',maxAge='120'].allowHeaders.[header='header1']"

appcmd.exe set config "contentSite" -section:system.webServer/cors /+"[origin='https://*.microsoft.com',allowCredentials='True',maxAge='120'].allowHeaders.[header='header2']"

appcmd.exe set config "contentSite" -section:system.webServer/cors /+"[origin='https://*.microsoft.com',allowCredentials='True',maxAge='120'].allowMethods.[method='DELETE']"

appcmd.exe set config "contentSite" -section:system.webServer/cors /+"[origin='https://*.microsoft.com',allowCredentials='True',maxAge='120'].exposeHeaders.[header='header1']"

appcmd.exe set config "contentSite" -section:system.webServer/cors /+"[origin='https://*.microsoft.com',allowCredentials='True',maxAge='120'].exposeHeaders.[header='header2']"

appcmd.exe set config "contentSite" -section:system.webServer/cors /+"[origin='http://*',allowed='False']"

PowerShell

Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors" -name "enabled" -value "True"
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors" -name "failUnlistedOrigins" -value "True"

Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors" -name "." -value @{origin='*'}

Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors" -name "." -value @{origin='https://*.microsoft.com';allowCredentials='True';maxAge=120}
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors/add[@origin='https://*.microsoft.com']/allowHeaders" -name "allowAllRequestedHeaders" -value "True"

Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors/add[@origin='https://*.microsoft.com']/allowHeaders" -name "." -value @{header='header1'}

Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors/add[@origin='https://*.microsoft.com']/allowHeaders" -name "." -value @{header='header2'}

Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors/add[@origin='https://*.microsoft.com']/allowMethods" -name "." -value @{method='DELETE'}

Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors/add[@origin='https://*.microsoft.com']/exposeHeaders" -name "." -value @{header='header1'}

Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors/add[@origin='https://*.microsoft.com']/exposeHeaders" -name "." -value @{header='header2'}

Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST/contentSite'  -filter "system.webServer/cors" -name "." -value @{origin='http://*';allowed='False'}