CORS
Acronymcross-origin-resource-sharing, same-origin policy, preflightDefinition
Cross-Origin Resource Sharing — the browser rule that a page on one origin (scheme, host and port) may not read a response from another unless that other server says so in a header; Access-Control-Allow-Origin is the server's consent, and the browser enforces it, not the server
The same-origin policy is the default and CORS is the opt-out, which is the part people get backward. A request the browser calls simple (a GET, a form POST) is sent and its response withheld; anything else — a JSON body, a custom header, a PUT — gets a preflight OPTIONS first, and the real request is sent only if the server answers with the allowed methods and headers. Credentials (cookies) need Access-Control-Allow-Credentials: true and a named origin, never *. None of this protects the server: curl ignores it. It protects the user, by stopping a page they happen to be on from reading their session at another site. On this site the API and the pages share one origin, so CORS never appears — until a second site, or an agent in a browser, wants the same routes.
"CORS error" in a console is the browser doing its job, and the fix is on the server the page tried to reach — not on the page. If you do not control that server, the answer is a proxy on your own origin, which is what the CORS error was there to make you think about.
The two paths a cross-origin request can take:
sequenceDiagram
participant P as Page (origin A)
participant B as Browser
participant S as Server (origin B)
alt Simple request: GET, or a plain form POST
P->>B: fetch()
B->>S: request, with Origin: A
S-->>B: response, maybe Access-Control-Allow-Origin
B-->>P: body only if the server allowed origin A
else Anything else: JSON body, custom header, PUT
P->>B: fetch(PUT, JSON)
B->>S: OPTIONS (preflight)
S-->>B: allowed origins, methods, headers
alt allowed
B->>S: PUT (the real request)
S-->>B: response
B-->>P: body
else not allowed
B-->>P: CORS error, and the real request is never sent
end
end
curl goes through none of this. CORS protects the user in a browser, not the server.