CORS (Cross-Origin Resource Sharing) lets a server tell the browser: "this other origin may read my responses". It works through response headers.
Why is it needed? Browsers apply the same-origin policy. An origin is the scheme, host and port, like https://app.com. A script can send requests to another origin. But it cannot read the response, unless the target server allows it. CORS is how the server allows it.
A PUT is not a simple request, so the browser first sends a preflight. A preflight is an OPTIONS request that asks for permission before the real request. It carries:
Origin: https://app.comAccess-Control-Request-Method: PUTAccess-Control-Request-Headers, which lists any custom headers
The server answers with:
Access-Control-Allow-OriginAccess-Control-Allow-MethodsAccess-Control-Allow-Headers- optionally
Access-Control-Max-Age, which lets the browser cache this answer
If the preflight approves, the browser sends the real PUT. The real response must also include Access-Control-Allow-Origin that matches the origin. If it doesn't, the browser hides the response from the script, and fetch rejects with a network error.
- CORS is a browser-enforced way to relax the same-origin policy.
- Non-simple requests make the browser send an OPTIONS preflight first.
- The server replies with
Access-Control-Allow-*headers. - The real response also needs
Access-Control-Allow-Origin. Access-Control-Max-Agelets the browser cache the preflight answer.