DEV Community

Cover image for Understanding Cross-Origin Resource Sharing (CORS)
adewaleomosanya
adewaleomosanya

Posted on

Understanding Cross-Origin Resource Sharing (CORS)

When building modern web applications, you’ll almost certainly run into CORS errors. They can be confusing at first, especially when your frontend and backend live on different domains.

In this post, I’ll explain what CORS is, why it exists, and how it works, with clear examples you can relate to.

What Is CORS?

Cross-Origin Resource Sharing (CORS) is a security mechanism based on HTTP headers that allows a server to specify which origins (domain, scheme, or port) are permitted to access its resources from a browser.

By default, browsers enforce the Same-Origin Policy, which prevents JavaScript running on one origin from accessing resources on another origin. CORS provides a controlled way to relax that restriction.

Example of a Cross-Origin Request


Frontend: https://domain-a.com
Backend API: https://domain-b.com/data.json

If JavaScript from domain-a.com tries to fetch data from domain-b.com, the browser will only allow it if the server responds with the correct CORS headers.

Why Browsers Enforce CORS

CORS exists to protect users from malicious websites stealing sensitive data such as:

  • Cookies.

  • Authentication tokens.

  • Private user information.

APIs like fetch() and XMLHttpRequest automatically follow CORS rules to reduce these risks.

What Requests Use CORS?

CORS applies to many browser features, including:

  • fetch() and XMLHttpRequest

  • Web fonts loaded via @font-face

  • WebGL textures

  • Images or videos drawn to a canvas

  • CSS shapes that use external images

How CORS Works

  1. The browser sends a request with an Origin header.

  2. The server responds with CORS headers (or none).

  3. The browser decides whether to allow JavaScript access to the response.

For some requests, the browser sends a preflight request first to ask the server for permission.

Simple Requests (No Preflight)

Some requests are considered simple and do not require a preflight.

Conditions for a Simple Request

  • Method is GET, HEAD, or POST

  • Only safe headers are used (e.g. Accept, Content-Type)

  • Content-Type is one of:

    1. application/x-www-form-urlencoded
    2. multipart/form-data
    3. text/plain

Example

fetch("https://bar.other/data.json")
  .then(res => res.json())
  .then(data => console.log(data));
Enter fullscreen mode Exit fullscreen mode

Request Sent by Browser

Origin: https://foo.example
Enter fullscreen mode Exit fullscreen mode

Server Response

Access-Control-Allow-Origin: *
Enter fullscreen mode Exit fullscreen mode

The browser allows the response to be read by JavaScript.

If the server wants to restrict access:

Access-Control-Allow-Origin: https://foo.example
Enter fullscreen mode Exit fullscreen mode

Preflighted Requests (OPTIONS)

Requests that can modify server data or use custom headers require a preflight.

What Triggers a Preflight?

  • HTTP methods like PUT, DELETE, or PATCH

  • Custom headers (e.g. Authorization, X-Custom-Header)

  • Non-simple Content-Type (e.g. application/json, text/xml)

Example Request

fetch("https://bar.other/doc", {
  method: "POST",
  headers: {
    "Content-Type": "text/xml",
    "X-PINGOTHER": "pingpong",
  },
  body: "<person><name>Arun</name></person>",
});
Enter fullscreen mode Exit fullscreen mode

Preflight Request (Sent Automatically)

OPTIONS /doc
Origin: https://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type, x-pingother
Enter fullscreen mode Exit fullscreen mode

Server Response

Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Enter fullscreen mode Exit fullscreen mode

If approved, the browser sends the actual request.

Credentialed Requests (Cookies & Auth)

By default, browsers do not send cookies in cross-origin requests.

To include credentials:

fetch(url, {
  credentials: "include"
});
Enter fullscreen mode Exit fullscreen mode

Required Server Headers

Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Credentials: true
Enter fullscreen mode Exit fullscreen mode

Important rules:

  • Access-Control-Allow-Origin cannot be *

  • Credentials + wildcard = blocked by browser

Common CORS Headers

Response Headers

  • Access-Control-Allow-Origin : Who can access the resource

  • Access-Control-Allow-Methods : Allowed HTTP methods

  • Access-Control-Allow-Headers : Allowed custom headers

  • Access-Control-Allow-Credentials : Allow cookies/auth

  • Access-Control-Max-Age : Cache preflight result duration

  • Access-Control-Expose-Headers : Headers visible to JS

Request Headers (Browser-Set)

  • Origin

  • Access-Control-Request-Method

  • Access-Control-Request-Headers

Top comments (0)