🌍 Fetch CORS in JavaScript – Complete Tutorial

CORS (Cross-Origin Resource Sharing) is a browser security mechanism that controls whether a web page can access resources from a different origin using APIs like fetch().

πŸ“Œ What is CORS?

CORS is a security feature implemented by browsers that allows or blocks cross-origin HTTP requests based on the response headers sent by the server.

>>"CORS is enforced by browsers to protect users from unauthorized cross-origin requests."

πŸ’‘ What is an Origin?

An origin is defined by the combination of:

  • 🌐 Protocol (HTTP or HTTPS)
  • 🏠 Domain (example.com)
  • πŸ”’ Port (80, 443, 3000, etc.)

πŸ“Š Same Origin vs Cross Origin

URL AURL BSame Origin?
https://example.comhttps://example.comβœ… Yes
https://example.comhttp://example.com❌ No (different protocol)
https://example.comhttps://api.example.com❌ No (different subdomain)
https://example.comhttps://example.com:3000❌ No (different port)

🌐 Basic Fetch Request

Simple Fetch

fetch("https://api.example.com/users")
  .then(response => response.json())
  .then(data => console.log(data));

If the server does not allow cross-origin requests from your website, the browser blocks access to the response.

🚫 Typical CORS Error

Browser Console

Access to fetch at
'https://api.example.com'
from origin
'https://mywebsite.com'
has been blocked by CORS policy.

πŸ›‘οΈ How CORS Works

When a cross-origin request is made:

  1. πŸ“€ The browser sends the HTTP request.
  2. πŸ–₯️ The server responds with CORS headers.
  3. βœ… If the headers allow the request, JavaScript can access the response.
  4. ❌ Otherwise, the browser blocks the response.

πŸ“‹ Important CORS Headers

HeaderPurpose
Access-Control-Allow-OriginSpecifies which origins are allowed.
Access-Control-Allow-MethodsLists allowed HTTP methods.
Access-Control-Allow-HeadersLists allowed request headers.
Access-Control-Allow-CredentialsAllows cookies and authentication credentials.
Access-Control-Max-AgeCaches preflight responses for a period of time.

βœ… Allowed Origin Example

Server Response Headers

Access-Control-Allow-Origin: https://mywebsite.com

🌍 Allow All Origins

Public API

Access-Control-Allow-Origin: *

Note

Using * allows any origin to access the resource. It cannot be combined with credentialed requests (credentials: "include").

βš™οΈ Fetch Options

Fetch with Options

fetch("https://api.example.com/users", {
  method: "GET",
  mode: "cors"
});

πŸ“Š Fetch Modes

ModeDescription
corsDefault for cross-origin requests. Uses the CORS protocol.
same-originAllows requests only to the same origin.
no-corsSends a limited request but returns an opaque response that JavaScript cannot meaningfully inspect.
navigateUsed internally for browser navigation, not for fetch().

πŸ” Sending Credentials

If cookies or HTTP authentication are required, include credentials in the request.

Fetch with Credentials

fetch("https://api.example.com/profile", {
  credentials: "include"
});

The server must also return:

Required Server Header

Access-Control-Allow-Credentials: true

✈️ Preflight Requests

Some requests require a preflight request. The browser sends an OPTIONS request first to check whether the actual request is allowed.

Requests That Commonly Trigger a Preflight

  • πŸ“€ Methods such as PUT, PATCH, or DELETE.
  • πŸ“ Custom request headers (for example, X-API-Key).
  • πŸ“¦ A Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain.

πŸ›  Example POST Request

POST Request

fetch("https://api.example.com/users", {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    name: "John"
  })
});

Because this request sends JSON, browsers typically perform a preflightOPTIONS request before sending the actual POST.

πŸš€ Complete Example

GET Data with Error Handling

async function loadUsers() {

  try {

    const response = await fetch(
      "https://api.example.com/users"
    );

    if (!response.ok) {
      throw new Error("Request failed");
    }

    const users =
      await response.json();

    console.log(users);

  } catch (error) {

    console.error(error);

  }

}

loadUsers();

πŸ“Š CORS vs Same-Origin Policy

FeatureSame-Origin PolicyCORS
PurposeRestricts cross-origin access by default.Provides a controlled way to allow cross-origin access.
Configured ByBrowserServer response headers
Default BehaviorBlocks accessAllows access only when permitted by the server

⚠️ Common Mistakes

  • ❌ Trying to "fix" CORS from frontend JavaScript. CORS is primarily controlled by the server.
  • ❌ Assuming mode: "no-cors" bypasses CORS restrictions. It does not provide access to the response body.
  • ❌ Using Access-Control-Allow-Origin: * together with credentialed requests.
  • ❌ Forgetting to configure the server to handle preflight OPTIONS requests.

Note

CORS is enforced by browsers. Server-to-server requests (such as backend API calls) are generally not restricted by the browser's CORS policy.

βœ… Best Practices

  • πŸ”’ Allow only trusted origins instead of using * whenever possible.
  • πŸ“‹ Handle preflight requests correctly on the server.
  • πŸͺ Use credentials only when necessary.
  • ⚑ Keep custom headers to a minimum to reduce unnecessary preflight requests.
  • πŸ›  Configure CORS on the backend rather than attempting to work around it in frontend code.

🎯 Summary

CORS is a browser security mechanism that works alongside the Same-Origin Policy to control cross-origin HTTP requests. When using theFetch API, the browser checks the server's CORS response headers before allowing JavaScript to access the response. Proper server-side CORS configuration is essential for secure communication between different origins.