CORS Explained

BY TOOLS.FUN  ·  MARCH 28, 2026  ·  6 min read

CORS — Cross-Origin Resource Sharing — is the mechanism that lets a web page on one origin make requests to a different origin. It is one of the most common sources of confusion for frontend developers, but once you understand the underlying Same-Origin Policy and how CORS headers work, the errors become easy to fix.

The Same-Origin Policy

Browsers enforce the Same-Origin Policy (SOP): JavaScript on https://app.example.com can freely fetch resources from the same origin but is blocked from reading responses from https://api.other.com. SOP prevents malicious sites from stealing data from authenticated sessions on other domains.

How CORS Relaxes the Restriction

CORS is an opt-in mechanism. The server at api.other.com can include response headers that tell the browser "this origin is allowed to read my responses." The key header is:

Access-Control-Allow-Origin: https://app.example.com

If the header is present and matches the requesting origin, the browser allows the JavaScript to read the response. Without it, the browser blocks access and logs the familiar CORS error.

Key point: CORS errors are enforced by the browser, not the server. The server receives and processes the request — it is the browser that blocks your JavaScript from reading the response.

Simple vs Preflight Requests

A "simple" request (GET or POST with standard content types like application/x-www-form-urlencoded) is sent directly. But if you set custom headers, use methods like PUT or DELETE, or send application/json, the browser first sends an OPTIONS preflight request to ask the server what is allowed. The server responds with headers like:

Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: Content-Type, Authorization Access-Control-Max-Age: 86400

You can inspect the full preflight exchange by converting your fetch call to cURL with the cURL Converter and sending the OPTIONS method manually.

Common CORS Headers

Access-Control-Allow-Origin — which origins can read responses. Access-Control-Allow-Methods — which HTTP methods are permitted. Access-Control-Allow-Headers — which request headers are allowed. Access-Control-Allow-Credentials — whether cookies are included. Access-Control-Expose-Headers — which response headers JavaScript can read. Access-Control-Max-Age — how long the preflight result is cached.

Credentials and Cookies

By default, cross-origin requests do not include cookies. To include them, the client must set credentials: 'include' in the fetch call, and the server must respond with Access-Control-Allow-Credentials: true. Critically, when credentials are used, Access-Control-Allow-Origin cannot be the wildcard * — it must specify the exact origin.

Key point: Using Access-Control-Allow-Origin: * with credentials is rejected by browsers. Always set the exact requesting origin when your API needs cookies or auth headers.

Common Errors and Fixes

"No Access-Control-Allow-Origin header" — the server is not sending CORS headers; add them in your API framework. "Preflight response is not successful" — the server is not handling OPTIONS requests; add an OPTIONS handler. "Credential is not supported if the CORS header Access-Control-Allow-Origin is *" — switch from wildcard to explicit origin. Use the JSON Formatter to inspect API error response bodies, which often contain clues about misconfigured CORS middleware.

Server Configuration Examples

In Express: app.use(cors({ origin: 'https://app.example.com', credentials: true })). In Nginx: add the headers in a location block. In Flask: use the flask-cors extension. Always restrict the allowed origin to your actual frontend domain rather than using a wildcard in production. You can use the Code Diff tool to compare your development and production CORS configurations side by side.

CORS for APIs and CDNs

Public APIs often use Access-Control-Allow-Origin: * because they serve any client. CDNs serving fonts or scripts also need CORS headers so browsers allow the cross-origin load. S3, Cloud Storage, and Azure Blob all have CORS configuration panels. Be precise: only allow the methods and headers your clients actually need.

Key point: CORS is not a security mechanism — it is a relaxation of one. The Same-Origin Policy is the security boundary; CORS pokes carefully controlled holes in it. Never use it as a substitute for proper authentication and authorisation.
← Back