CORS
Cross-Origin Resource Sharing (CORS ↗) is a mechanism that uses HTTP headers to grant a web application running on one origin permission to reach selected resources in a different origin. The web application executes a cross-origin HTTP request when it requests a resource that has a different origin from its own, including domain, protocol, or port.
For a CORS request to reach a site protected by Access, the request must include a valid CF-Authorization
cookie. This may require additional configuration depending on the type of request:
-
Simple requests ↗ are sent directly to the origin, without triggering a preflight request. For configuration instructions, refer to Allow simple requests.
-
Preflighted requests ↗ cause the browser to send an OPTIONS request before sending the actual request. The OPTIONS request checks which methods and headers are allowed by the origin. For configuration instructions, refer to Allow preflighted requests.
If you make a simple CORS request to an Access-protected domain and have not yet logged in, the request will return a CORS error
. There are two ways you can resolve this error:
- Option 1 — Log in and refresh the page.
- Option 2 — Create a Cloudflare Worker which automatically sends an authentication token. This method only works if both sites involved in the CORS exchange are behind Access.
- Visit the target domain in your browser. You will see the Access login page.
- Log in to the target domain. This generates a
CF-Authorization
cookie. - Refresh the page that made the CORS request. The refresh resends the request with the newly generated cookie.
If you make a preflighted cross-origin request to an Access-protected domain, the OPTIONS request will return a 403
error. This error occurs regardless of whether you have logged in to the domain. This is because the browser never includes cookies with OPTIONS requests, by design. Cloudflare will therefore block the preflight request, causing the CORS exchange to fail.
There are three ways you can resolve this error:
- Option 1 — Bypass OPTIONS requests to origin.
- Option 2 - Configure Cloudflare to respond to the OPTIONS request.
- Option 3 — Create a Cloudflare Worker which automatically sends an authentication token. This method only works if both sites involved in the CORS exchange are behind Access.
You can configure Cloudflare to send OPTIONS requests directly to your origin server. To bypass Access for OPTIONS requests:
- In Zero Trust ↗, go to Access > Applications.
- Locate the origin that will be receiving OPTIONS requests and select Edit.
- In the Settings tab, scroll down to CORS settings.
- Turn on Bypass options requests to origin. This will remove all existing CORS settings for this application.
It is still important to enforce CORS for the Access JWT — this option should only be used if you have CORS enforcement established in your origin server.
You can configure Cloudflare to respond to the OPTIONS request on your behalf. The OPTIONS request never reaches your origin. After the preflight exchange resolves, the browser will then send the main request which does include the authentication cookie (assuming you have logged into the Access-protected domain).
To configure how Cloudflare responds to preflight requests:
-
In Zero Trust ↗, go to Access > Applications.
-
Locate the origin that will be receiving OPTIONS requests and select Edit.
-
In the Settings tab, scroll down to CORS settings.
-
Configure the dashboard CORS settings ↗ to match the response headers sent by your origin.
For example, if you have configured
api.mysite.com
to return the following headers:then go to
api.mysite.com
in Access and configure Access-Control-Allow-Origin, Access-Control-Allow-Credentials, Access-Control-Allow-Methods, and Access-Control-Allow-Headers. -
Select Save application.
-
(Optional) You can check your configuration by sending an OPTIONS request to the origin with
curl
. For example,should return a response similar to:
If you have two sites protected by Cloudflare Access, example.com
and api.mysite.com
, requests made between the two will be subject to CORS checks. Users who log in to example.com
will be issued a cookie for example.com
. When the user’s browser requests api.mysite.com
, Cloudflare Access looks for a cookie specific to api.mysite.com
. The request will fail if the user has not already logged in to api.mysite.com
.
To avoid having to log in twice, you can create a Cloudflare Worker that automatically sends authentication credentials to api.mysite.com
.
- Workers account
wrangler
installationexample.com
andapi.mysite.com
domains protected by Access
Follow these instructions to generate a new Access service token. Copy the Client ID
and Client Secret
to a safe place, as you will use them in a later step.
-
In Zero Trust ↗, go to Access > Applications.
-
Find your
api.mysite.com
application and select Edit. -
Select the Policies tab.
-
Add the following policy:
Action Rule type Selector Service Auth Include Service Token
Open a terminal and run the following command:
This will prompt you to install the create-cloudflare
↗ package and lead you through setup.
For setup, select the following options:
- For What would you like to start with?, choose
Hello World example
. - For Which template would you like to use?, choose
Hello World Worker
. - For Which language do you want to use?, choose
JavaScript
. - For Do you want to use git for version control?, choose
Yes
. - For Do you want to deploy your application?, choose
No
(we will be making some changes before deploying).
Go to your project directory.
Open /src/index.js
and delete the existing code and paste in the following example:
Then, deploy the Worker to your Cloudflare account:
-
Log in to the Cloudflare dashboard ↗, select your account and go to Workers & Pages.
-
Select your newly created Worker.
-
In the Triggers tab, go to Routes and add
example.com/api/*
. The Worker is placed on a subpath ofexample.com
to avoid making a cross-origin request. -
In the Settings tab, select Variables.
-
Under Environment Variables, add the following secret variables:
CF_ACCESS_CLIENT_ID
=<service token Client ID>
CF_ACCESS_CLIENT_SECRET
=<service token Client Secret>
The Client ID and Client Secret are copied from your service token.
- Enable the Encrypt option for each variable and select Save.
Modify your example.com
application to send all requests to example.com/api/
instead of api.mysite.com
.
HTTP requests should now work seamlessly between two different Access-protected domains. When a user logs in to example.com
, the browser makes a request to the Worker instead of to api.mysite.com
. The Worker adds the Access service token to the request headers and then forwards the request to api.mysite.com
. Since the service token matches a Service Auth policy, the user no longer needs to log in to api.mysite.com
.
In general, we recommend the following steps when troubleshooting CORS issues:
- Capture a HAR file with the issue described, as well as the JS console log output recorded simultaneously. This is because the HAR file alone will not give full visibility on the reason behind cross-origin issues.
- Ensure that the application has set
credentials: 'same-origin'
in all fetch or XHR requests. - If you are using the cross-origin setting ↗ on script tags, these must be set to “use-credentials”.