The CORS Error You've Seen

Access to fetch at 'https://api.example.com/users' from origin 'https://app.mysite.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

This error means: your JavaScript on app.mysite.com tried to read a response from api.example.com, but the server did not return headers giving permission. The browser blocked it.

What is the Same-Origin Policy?

Browsers enforce the Same-Origin Policy: JavaScript on one origin cannot read responses from a different origin. An origin is defined as: scheme + hostname + port.

URLSame origin as https://example.com?Reason
https://example.com/pageYesSame scheme, host, port
http://example.comNoDifferent scheme (http vs https)
https://api.example.comNoDifferent subdomain
https://example.com:8080NoDifferent port
https://other.comNoDifferent host

How CORS Works

CORS lets servers relax the same-origin policy selectively. The server adds response headers to say which origins are allowed:

Server response headers that enable CORS Access-Control-Allow-Origin: https://app.mysite.com Access-Control-Allow-Methods: GET, POST, PUT, DELETE Access-Control-Allow-Headers: Authorization, Content-Type Access-Control-Max-Age: 86400

When the browser sees Access-Control-Allow-Origin matching the current origin, it allows JavaScript to read the response.

Simple vs Preflight Requests

Simple requests (no preflight)

Requests meeting ALL of these conditions skip preflight:

  • Method is GET, POST, or HEAD
  • Content-Type is text/plain, multipart/form-data, or application/x-www-form-urlencoded
  • No custom headers (no Authorization, no custom X-headers)

Complex requests (preflight required)

Anything else triggers an automatic OPTIONS preflight first:

Browser auto-sends OPTIONS request before your fetch() OPTIONS /api/users HTTP/1.1 Origin: https://app.mysite.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: Authorization, Content-Type
Server must respond with approval HTTP/1.1 204 No Content Access-Control-Allow-Origin: https://app.mysite.com Access-Control-Allow-Methods: GET, POST, PUT, DELETE Access-Control-Allow-Headers: Authorization, Content-Type Access-Control-Max-Age: 86400

How to Fix CORS — By Framework

Node.js / Express

npm install cors const cors = require('cors'); // Allow specific origin app.use(cors({ origin: 'https://app.mysite.com' })); // Allow multiple origins app.use(cors({ origin: ['https://app.mysite.com', 'https://admin.mysite.com'], methods: ['GET','POST','PUT','DELETE'], allowedHeaders: ['Authorization','Content-Type'], credentials: true // if using cookies/auth headers }));

Nginx

nginx.conf location /api/ { add_header 'Access-Control-Allow-Origin' 'https://app.mysite.com'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type'; if ($request_method = OPTIONS) { add_header 'Access-Control-Max-Age' 86400; return 204; } }

PHP

PHP — add to top of API file header('Access-Control-Allow-Origin: https://app.mysite.com'); header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS'); header('Access-Control-Allow-Headers: Authorization, Content-Type'); if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(204); exit; }

⚠️ Never Use * With Credentials

If your request includes cookies or an Authorization header (credentials: 'include' in fetch), you cannot use Access-Control-Allow-Origin: *. You must specify the exact origin AND add Access-Control-Allow-Credentials: true.

💡 CORS is a Browser Feature, Not a Server Feature

CORS errors only appear in browsers. Server-to-server requests, Postman, and curl are never blocked by CORS — only browser JavaScript is. If your API needs to prevent unauthorised server-to-server access, use API keys or OAuth, not CORS.

How We Research and Update This Guide

We test the underlying formula or workflow, compare outputs with reliable references, and revise examples whenever the page content changes.

  • The workflow or formula is tested directly in the tool and compared against independent reference examples.
  • Examples are kept practical so readers can verify the result without hidden assumptions.
  • Pages are revised whenever the interface, calculation flow, or surrounding guidance materially changes.

Frequently Asked Questions — CORS