SharePoint 2019 CORS Requests

In SharePoint 2019 (or 2016), when someone is trying to access REST API from other domain, it is usually blocked by browsers CORS policy. To avoid these blocking, you must configure your SharePoint IIS Server to handle and change some HTTP Headers.

1. Install IIS rewrite module

First of all, you must install IIS Rewrite module for handling and changing HTTP Request Headers. It can be downloaded and installed from here – https://www.iis.net/downloads/microsoft/url-rewrite

2. Configure Server Variables

Now, you must define some Server Variables, that will be using our rewrite rules. It can be done easily in IIS Server Manager:
– SP_CAPTURED_ACCESS_CONTROL_REQUEST_HEADERS
– SP_CAPTURED_ACCESS_CONTROL_REQUEST_METHOD
– SP_CAPTURED_ORIGIN
– HTTP_ORIGIN

3. Configure Rewrite Rules

Now, we have our variables ready to use, we must define our rewrite rules for HTTP Headers. This can be done easily by editing web.config of our SharePoint IIS site. We will be inserting these <rewrite> block into <system.webServer> element.

Note: you must change the <YOUR ORIGIN ADDRESS> text to your actual URL, from where will be requests on SharePoint site for example you can change it to look like this: <add input=”{HTTP_ORIGIN}” pattern=”https://other.domain.com” />

<rewrite>
  <rules>
    <clear />
    <rule name="SP: Capture HTTP Origin" enabled="true">
      <match url="^(?:.+/)?_api/.+" />
      <conditions>
        <add input="{HTTP_ORIGIN}" pattern="<YOUR ORIGIN ADDRESS>" />
      </conditions>
      <serverVariables>
        <set name="SP_CAPTURED_ORIGIN" value="{C:0}" />
      </serverVariables>
      <action type="None" />
    </rule>
    <rule name="SP: Capture Access-Control-Request-Method" enabled="true">
      <match url=".*" />
      <conditions>
        <add input="{SP_CAPTURED_ORIGIN}" pattern=".+" />
        <add input="{HTTP_ACCESS_CONTROL_REQUEST_METHOD}" pattern=".+" />
      </conditions>
      <serverVariables>
        <set name="SP_CAPTURED_ACCESS_CONTROL_REQUEST_METHOD" value="{C:0}" />
      </serverVariables>
      <action type="None" />
    </rule>
    <rule name="SP: Capture Access-Control-Request-Headers" enabled="true">
      <match url=".*" />
      <conditions>
        <add input="{SP_CAPTURED_ORIGIN}" pattern=".+" />
        <add input="{HTTP_ACCESS_CONTROL_REQUEST_HEADERS}" pattern=".+" />
      </conditions>
      <serverVariables>
        <set name="SP_CAPTURED_ACCESS_CONTROL_REQUEST_HEADERS" value="{C:0}" />
      </serverVariables>
      <action type="None" />
    </rule>
    <rule name="SP: Handle OPTIONS request" enabled="true" stopProcessing="true">
      <match url=".*" />
      <conditions>
        <add input="{SP_CAPTURED_ORIGIN}" pattern=".+" />
        <add input="{REQUEST_METHOD}" pattern="OPTIONS" />
      </conditions>
      <action type="CustomResponse" statusCode="200" statusReason="preflight" statusDescription="preflight" />
    </rule>
    <rule name="SP: Hide HTTP Origin" enabled="true">
      <match url=".*" />
      <conditions>
        <add input="{SP_CAPTURED_ORIGIN}" pattern=".+" />
      </conditions>
      <serverVariables>
        <set name="HTTP_ORIGIN" value="" />
      </serverVariables>
      <action type="None" />
    </rule>
  </rules>
  <outboundRules>
    <preConditions>
      <preCondition name="allowedOrigin">
        <add input="{SP_CAPTURED_ORIGIN}" pattern=".+" />
      </preCondition>
    </preConditions>
    <rule name="SP: Set Access-Control-Allow-Origin to allowed origin" enabled="true" preCondition="allowedOrigin">
      <match serverVariable="RESPONSE_Access-Control-Allow-Origin" pattern=".*" negate="false" />
      <conditions>
        <add input="{SP_CAPTURED_ORIGIN}" pattern=".+" />
      </conditions>
      <action type="Rewrite" value="{C:0}" />
    </rule>
    <rule name="SP: Set Access-Control-Allow-Credentials for allowed origin" enabled="true" preCondition="allowedOrigin">
      <match serverVariable="RESPONSE_Access-Control-Allow-Credentials" pattern="^$" negate="false" />
      <action type="Rewrite" value="true" />
    </rule>
    <rule name="SP: Set Access-Control-Allow-Methods for allowed origin" enabled="true" preCondition="allowedOrigin">
      <match serverVariable="RESPONSE_Access-Control-Allow-Methods" pattern="^$" negate="false" />
      <conditions>
        <add input="{SP_CAPTURED_ACCESS_CONTROL_REQUEST_METHOD}" pattern=".+" />
      </conditions>
      <action type="Rewrite" value="{C:0}" />
    </rule>
    <rule name="SP: Set Access-Control-Allow-Headers for allowed origin" enabled="true" preCondition="allowedOrigin">
      <match serverVariable="RESPONSE_Access-Control-Allow-Headers" pattern="^$" negate="false" />
      <conditions>
        <add input="{SP_CAPTURED_ACCESS_CONTROL_REQUEST_HEADERS}" pattern=".+" />
      </conditions>
      <action type="Rewrite" value="{C:0}" />
    </rule>
    <rule name="SP: Set Access-Control-Max-Age to allow caching of preflight" enabled="true" preCondition="allowedOrigin">
      <match serverVariable="RESPONSE_Access-Control-Max-Age" pattern="^$" negate="false" />
      <conditions logicalGrouping="MatchAny">
        <add input="{SP_CAPTURED_ACCESS_CONTROL_REQUEST_METHOD}" pattern=".+" />
        <add input="{SP_CAPTURED_ACCESS_CONTROL_REQUEST_HEADERS}" pattern=".+" />
      </conditions>
      <action type="Rewrite" value="86400" />
    </rule>
  </outboundRules>
</rewrite>

Now, the CORS requests to our SharePoint 2019 site should be ready and functional.

Marek

Currently working as SharePoint Developer combining both back-end & front-end development scenarios. Also enthusiastic about Office 365 & Azure solutions.

You may also like...

6 Responses

  1. Brett B says:

    Thanks a lot for posting this, Marek – we SharePoint server admins are always trying to find ways to fix Microsoft’s latest security “enhancements”!

    I’m fairly certain that Microsoft doesn’t support using the IIS ReWrite module in SharePoint, so I did some more research and testing on this, just to see if there was another option. In SharePoint 2016, HSTS was introduced to force client connections to use HTTPS, but I could never get it to function properly. See Trevor Seward’s post about setting it up: https://thesharepointfarm.com/2016/04/enabling-http-strict-transport-security-for-sharepoint-server-2016/

    It appears that setting up HSTS in IIS 10 on Windows 2019 and then setting up the SharePoint 2019 web app for HSTS via Trevor’s post can eliminate the CORS errors the same way your solution can, however. Here’s what I did to set it up:
    Per Trevor’s post (except Max Age), setup the web app for HSTS:
    $wa = Get-SPWebApplication https://hubdxfer.pcapkg.com
    $wa.HttpStrictTransportSecuritySettings.MaxAge = 0
    $wa.Update()

    IIS 10 on the web front end servers that host the site, setup bindings for both HTTP port 80 and HTTPS port 443 (bind to a valid cert). Highlight the site in IIS, and click HSTS under Configure (which only appears in IIS 10 on Windows 2019).
    Click Enable, set max age to 0, and enable Redirect HTTP to HTTPS.
    More details on HSTS in IIS 10.0 v1709 and later: https://docs.microsoft.com/en-us/iis/configuration/system.applicationhost/sites/site/hsts

    My perspective on max-age: If you set max age to a value higher than 0, the client will check the server the first time it goes to the web app address to find out if it should redirect to HTTPS but on subsequent visits, it won’t check with the server again until after that time frame expires. This messes with testing results because if you change something on the server, the client keeps trying to access HTTPS for the web app regardless of what the server is set to, exactly like the max age parameter in web.config for blob cache. I always want clients to pickup changes from the server immediately, so I always set max age to 0 for both of these settings.

    I’m very interested to know if you (or anyone else) see different results or know of problems that may arise when doing it the way I’ve described, as I am about to implement this on five SharePoint 2019 farms in my production environment. Thanks & happy SharePointing!

  2. SharePoint Server 2016 and 2019 have build in CORS support. The method above is not recommended.
    Instead the build in CORS Support should be enabled using the following powershell command:

    $stsConfig = Get-SPSecurityTokenServiceConfig
    $stsConfig.ActivateOkResponseToCORSOptions = $true
    $stsConfig.Update();

    Be aware that the build-in CORS implementation requires OAUTH as supported authentication method as this is the only reliable authentication method cross domain and security boundary.

    The method above effectively disables the built in security mechanims in SharePoint as it prevents SharePoint from detecting the CORS request.

    • yehiel tapiro says:

      Hi Stefan,
      we have sharepoint 2019 on-prem and i cant find property ‘ActivateOkResponseToCORSOptions’.
      getting this error:
      The property ‘ActivateOkResponseToCORSOptions’ cannot be found on this object. Verify that the property exists and can
      be set.
      At line:1 char:1
      + $stsConfig.ActivateOkResponseToCORSOptions = $true
      + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      + CategoryInfo : InvalidOperation: (:) [], RuntimeException
      + FullyQualifiedErrorId : PropertyAssignmentException

      i need to allow cors in our farm.
      can you guid me?

  3. Stas says:

    After week of research, this one resolve my issue of crud operations between two different wep apps in sharepoint.

  4. Heta77 says:

    Your Solution works well, but You must install IIS CORS Module and to modify web.config:

  5. Heta77 says:

    Your Solution works well, but You must install IIS CORS Module and to modify web.config:

Leave a Reply

Your email address will not be published. Required fields are marked *