Skip to main content

Cross-Origin Resource Sharing



You don't need that CORS request

Routing to and moving over the JavaScript clients using the api. subdomain will cut your network traffic in half.

Cache your CORS -

What is the motivation behind the introduction of preflight CORS requests? -

Express.js app example:

NodeJS reverse proxy which adds CORS headers to the proxied request:


By following the Same-origin policy, by default browsers restrict one origin to access resources of another origin. CORS allows to lift this restriction.

Same-origin policy

a critical security mechanism that restricts how a document or script loaded by one origin can interact with a resource from another origin

Is considered same-origin if only the path differs. Different origin (ie cross-origin) is:

  • Different domain: and
  • Different subdomain: and
  • Different port: and
  • Different protocol/scheme: and



See which conditions dictate if a request is simple or preflighted here:

Simple requests

  1. The browser sends a request with the Origin header.
  2. The server checks the Origin request header responds with either:
    • (Success) The data + the header Access-Control-Allow-Origin: * if requests from all domains are allowed.
    • (Success) The data + the header Access-Control-Allow-Origin: if requests from the origin specified at the Origin header are allowed. The Access-Control-Allow-Origin value is the same than the Origin header of the request.
    • An error if cross-origin requests from the specified Origin are not allowed.
> Client Request >
GET /api/recipes HTTP/1.1

< Server Response <
HTTP/1.1 200 OK

Preflighted requests

For any request with Content-Type: application/json or custom headers (among other conditions).

  1. The browser performs an OPTIONS method preflight request. This request specifies which headers and HTTP method will be used in the actual request, using the headers Access-Control-Request-Headers and Access-Control-Request-Method.
  2. The server responds to the OPTIONS request with a response that has the headers Access-Control-Allow-Origin, Access-Control-Allow-Methods and Access-Control-Allow-Headers, and a status of 204 No Content.
  3. If allowed, then the browser makes the actual request, otherwise the actual request fails.

If the value of Access-Control-Allow-Origin is a single origin (ie is not *), the response to both requests should also set the header Vary: Origin "to indicate to clients that server responses will differ based on the value of the Origin request header". source

> Preflight Request >
OPTIONS /api/recipes HTTP/1.1
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type

< Preflight Response <
HTTP/1.1 204 No Content
Access-Control-Allow-Methods: GET,POST,PUT,DELETE
Access-Control-Allow-Headers: Content-Type
Vary: Origin

> Actual Request >
POST /api/recipes HTTP/1.1
Content-Type: application/json

< Actual Response <
HTTP/1.1 201 Created
Vary: Origin

Note that there will be many more headers in addition to these.


Request headers:

  • Origin
  • Access-Control-Request-Method
  • Access-Control-Request-Headers

Response headers:

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Credentials
  • Access-Control-Expose-Headers
  • Access-Control-Max-Age
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers

Origin request header

indicates the origin (scheme, hostname, and port) that caused the request

All CORS requests must have an Origin header. source

Origin: http://localhost:3000

Access-Control-Allow-Origin response header

What client domains are allowed by the server.

  • Access-Control-Allow-Origin: * -> Requests from all domains allowed. Only for public APIs that can be accessed from any site.
  • Access-Control-Allow-Origin: -> This domain is allowed. "Only a single origin can be specified. If the server supports clients from multiple origins, it must return the origin for the specific client making the request." source
  • Access-Control-Allow-Origin: null -> Should not be used.

Access-Control-Allow-Methods response header

Which HTTP request methods are allowed.

Response to a preflight request.

Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Methods: *

Access-Control-Allow-Headers response header

What HTTP request headers are allowed.

Response to a preflight request.

Important for custom headers.

CORS-safelisted request headers

Access-Control-Allow-Headers: Content-Type, X-Custom-Header
Access-Control-Allow-Headers: *

Access-Control-Allow-Credentials response header

Access-Control-Allow-Credentials: true (value can only be true)


At the browser console:

  • (Chrome) Access to XMLHttpRequest at 'http://localhost:5000/api/recipes' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
  • (Safari) Failed to load resource: Origin http://localhost:3000 is not allowed by Access-Control-Allow-Origin. Status code: 200. (This is for the axios request GET http://localhost:5000/api/recipes)
  • (Safari) XMLHttpRequest cannot load http://localhost:5000/api/recipes due to access control checks.