What is CORS?

CORS stands for Cross-Origin Resource Sharing. It is how a server tells your browser: "pages from this other site are allowed to read my answers." Without that permission, the browser keeps the answer away from the page's JavaScript.

The rule underneath: same-origin policy

An origin is the scheme, host and port together: https://app.example.com. Two addresses are the same origin only if all three match. By default a page may only read responses from its own origin. That stops a random page you open from quietly reading your webmail or your bank in the background, using the cookies already in your browser.

Note what it does not stop: the request itself. A cross-origin request usually still goes out and the server still processes it. The browser simply refuses to hand the response back to the page. That is why a "blocked by CORS" error in the console often sits next to a 200 in the network panel.

How a server opts in

By sending headers with its response:

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: X-Total-Count
HeaderWhat it means
Allow-OriginWhich origin may read the response. One origin, or * for "anyone" (but never * together with credentials).
Allow-MethodsWhich methods are allowed, answered during the preflight.
Allow-HeadersWhich request headers the page may set.
Allow-CredentialsWhether cookies and auth headers may be sent and the response read.
Expose-HeadersWhich response headers JavaScript may read. By default it sees only a handful.

Simple requests and preflights

Some requests go straight out. Others are checked first with an OPTIONS request called a preflight, which asks the server whether the real request is allowed.

A request stays "simple" only if it is GET, HEAD or POST, its Content-Type is one of text/plain, application/x-www-form-urlencoded or multipart/form-data, and it sets no unusual headers. Send JSON, use PUT or DELETE, or add Authorization, and the browser preflights.

You can see which case you are in, live, with our CORS tester.

Credentials change the rules

With credentials: "include" the browser sends cookies. Then the server must name your exact origin (no *) and send Access-Control-Allow-Credentials: true, or the read is refused. This is deliberate: * plus cookies would let any site read your logged-in data.

What CORS is not

Getting an error right now?

The fixes, in order, with code: CORS error: what it means and how to fix it. To see what your own request does: CORS tester. Testing against a server you cannot change: HeaderForge can add the headers in your own browser, one click, one site.

More on this topic: Preflight request (CORS OPTIONS): when it happens and how to fix it · How to disable CORS in Chrome (and the safer way to test) · How to disable CORS in Firefox (and why content.cors.disable makes it worse) · TypeError: Failed to fetch — what it actually means, and how to tell which cause