Loading...

CDN.com.tr Help

CORS headers at the edge

Add Access-Control-Allow-Origin and the other CORS headers to a delivery rule's responses, let your origin answer preflight OPTIONS requests, and allow the methods your API uses in the WAF.

CORS headers at the edge

Add Access-Control-Allow-Origin and the other CORS headers to a delivery rule's responses, let your origin answer preflight OPTIONS requests, and allow the methods your API uses in the WAF.

Related guides

How CORS works in the browser, how to read a request the edge refused, and what else your origin receives from the edge.

Background

What is CORS? The browser rule behind every cross-origin error

Simple requests, preflights and credentials, with curl tests.

Read the guide
A 403 from the edge

Read WAF logs

Find a refused request by time or Reference ID and see which rule blocked it.

Open the topic
Your origin

Origin connection: the real visitor IP, locking down your origin, WebSocket and timeouts

Headers sent to your origin, and the WAF methods an API needs.

Open the topic

Panel path

  1. Management Panel
  2. Delivery Rules
  3. Rules
  4. Edit
  5. Headers
  6. Add response headers

Prerequisites

  • A delivery rule that serves the paths the other site requests.
  • The exact origin of the requesting site, such as https://app.example.com, or * for files anyone may load.
  • For API calls that send a preflight: your origin answers OPTIONS on those paths with 200 or 204.
  • The owner or editor role: viewers can see rules but cannot change them.

Decision model

Public files or an API?

What the browser sends decides where the work happens.

  • Fonts, images and public JSON loaded with a plain GET: no preflight, and Access-Control-Allow-Origin in the rule is all they need. While account-wide image optimization is on, .jpg, .jpeg and .png files take the response headers of the domain's oldest rule, not of the rule for their path.
  • API calls with JSON bodies, custom headers or PUT, PATCH, DELETE: the browser sends a preflight first; your origin answers it, and the rule can add the CORS headers to that answer.
  • Requests with cookies or other credentials: one named origin, not *, plus Access-Control-Allow-Credentials true.

Each header from the edge or from your origin?

Pick one source per header.

  • Edge (the rule): one fixed value on every 2xx and 3xx response, cache hits included, and on your origin's 4xx and 5xx responses too when the line ends with always.
  • Origin: a value that depends on the requesting site, sent with Vary: Origin.
  • Sent by both: tick it under Remove headers, so only the rule's value goes out.

Step-by-step guide

1

Add the headers to the rule

Example for an API under /api/ that one web app calls. Write one header per line; a value with spaces goes in double quotes.

  • Open Delivery Rules → Rules and press Edit on the rule for /api/.
  • Under Then → Headers, write in Add response headers, each on its own line: Access-Control-Allow-Origin https://app.example.com, Access-Control-Allow-Methods "GET, POST, PUT, OPTIONS", Access-Control-Allow-Headers "Content-Type, Authorization" and Access-Control-Max-Age 600.
  • Under Remove headers, tick any of these names your origin also sends.
  • Press Save rule.

Expected result: The rule shows a chip such as +4 response headers, and the page shows Live once the edge serves it.

2

Allow the API's methods in the WAF

Needed while the site-wide WAF is on and the API uses methods beyond GET, HEAD, POST and OPTIONS.

  • In the sidebar, open Security under Protection.
  • Under Allowed HTTP methods, tick PUT, PATCH or DELETE as your API needs, keep OPTIONS ticked, and press Save.

Expected result: The panel confirms the save, and the change propagates within 1-2 minutes.

3

Check a simple request and a preflight

curl does not enforce CORS, so it shows exactly what the edge answers.

  • Request the endpoint with an Origin header.
  • Send the preflight a browser would send: OPTIONS with Origin, Access-Control-Request-Method and Access-Control-Request-Headers.

Expected result: The simple request carries one access-control-allow-origin. The preflight answers 200 or 204 with the allowed origin, methods and headers.

cdnctl equivalent
curl -s -o /dev/null -D - -H 'Origin: https://app.example.com' https://www.example.com/api/items | grep -iE '^(HTTP|access-control)'
curl -s -o /dev/null -D - -X OPTIONS -H 'Origin: https://app.example.com' -H 'Access-Control-Request-Method: PUT' -H 'Access-Control-Request-Headers: content-type' https://www.example.com/api/items | grep -iE '^(HTTP|access-control|x-mt-blocked-by)'

Verification

  • curl -s -o /dev/null -D - -H 'Origin: https://app.example.com' https://www.example.com/api/items | grep -iE '^(HTTP|access-control)' → 2xx and exactly one access-control-allow-origin: https://app.example.com
  • curl -s -o /dev/null -D - -X OPTIONS -H 'Origin: https://app.example.com' -H 'Access-Control-Request-Method: PUT' -H 'Access-Control-Request-Headers: content-type' https://www.example.com/api/items | grep -iE '^(HTTP|access-control|x-mt-blocked-by)' → 200 or 204 with access-control-allow-origin, access-control-allow-methods and access-control-allow-headers
  • A 403 with x-mt-blocked-by: cdn-edge-security on a request → the edge refused it (the WAF, or an IP, country, network or hotlink block); check Allowed HTTP methods and WAF logs

Use cases

A web app on app.example.com loads fonts, JSON or API responses from www.example.com, and the browser blocks them with a CORS error.

Quick workflow

  1. Open Delivery Rules, go to the Rules tab and press Edit on the rule that serves the paths the other site requests, or Add rule for a new path.
  2. Under Then, open Headers and write one header per line in Add response headers as Header-Name value, without a colon, for example Access-Control-Allow-Origin https://app.example.com. A value with spaces goes in double quotes.
  3. If your origin already sends an Access-Control-* header for these paths, tick the same name under Remove headers, so the browser receives a single value.
  4. Press Save rule (Create rule for a new rule) and wait until the page shows Live.
  5. If your API uses PUT, PATCH or DELETE and the site-wide WAF is on, tick them under Allowed HTTP methods on the Security page.
  6. Check a simple request and a preflight with curl.

Checks

  • The rule's headers are added to successful and redirect responses (2xx and 3xx), cache hits included, from the moment the rule is published. A line that ends with always is also added to your origin's 4xx and 5xx responses.
  • Preflight OPTIONS requests go to your origin and are never cached. When your origin answers a preflight with 200 or 204, the rule's headers are added to that answer; a preflight answered with 401, 404 or 405 reaches the browser without them, unless the line ends with always. On a rule with Password protection or an IP allow list, the edge itself answers a preflight it does not let through, with 401 or 403.
  • Exactly one Access-Control-Allow-Origin reaches the browser: with two values, the browser rejects the response.
  • If your origin varies Access-Control-Allow-Origin by the requesting site, it must also send Vary: Origin. The edge keeps those variants apart as long as Keep one cached copy whatever the Vary header says is off on the rule.
  • Leave Access-Control-Request-Method and Access-Control-Request-Headers unticked under Remove headers: the names ticked there are also removed from the requests sent to your origin, and your origin reads these two to answer a preflight.
  • With the site-wide WAF on, GET, HEAD, POST and OPTIONS are allowed by default. A request with a method that is not on the list gets a 403 with no CORS headers and with X-MT-Blocked-By: cdn-edge-security, which the browser reports as a CORS error.
  • While account-wide image optimization is on, .jpg, .jpeg and .png files get the response headers of the domain's oldest rule, not of the rule for their path: put the CORS header for those images on that rule, with a fixed Access-Control-Allow-Origin. When that oldest rule is the certificate-check rule, they get no rule headers.

Frequently asked questions

Does the edge answer preflight requests itself?

The edge passes OPTIONS requests to your origin and never caches them, so your origin must answer the preflight with 200 or 204. The rule's response headers are added to that answer: the CORS headers can come from the rule, and your origin only has to accept OPTIONS. The exception: on a rule with Password protection or an IP allow list, the edge itself answers a preflight it does not let through, with 401 or 403.

Can one rule allow several sites?

A rule adds the same value to every response: * or one origin such as https://app.example.com. To allow several origins, let your application send the matching origin together with Vary: Origin, and leave Access-Control-Allow-Origin out of the rule. Requests with cookies or other credentials need a named origin, not *.

The browser still reports a CORS error. What do I check?

Start with the status of the failing request in the browser's network panel. A 403 with X-MT-Blocked-By: cdn-edge-security comes from the edge: look it up in WAF logs, and if its method is missing, add it under Allowed HTTP methods. By default, any other 4xx or 5xx arrives without the rule's headers, so fix that response first. A line that ends with always, such as Access-Control-Allow-Origin https://app.example.com always, is also added to your origin's 4xx and 5xx responses. Then check that exactly one Access-Control-Allow-Origin arrives and that it matches the requesting site, scheme included.

My API uses PUT, PATCH or DELETE. What do I change?

While the site-wide WAF is on, open the Security page, tick the methods under Allowed HTTP methods and press Save; the change propagates within 1-2 minutes. Allowed request methods on the Security tab of Delivery Rules opens the same card. Keep OPTIONS ticked: browsers send it for preflights.