ON THIS PAGE (7 SECTIONS)
- ✓CORS is enforced by the browser, for responses read by scripts. Non-browser clients ignore it.
- ✓Allowing an origin is not authentication. A logged-out browser on an allowed site is still logged out.
- ✓Reflecting the request Origin with credentials enabled lets any site act as the user.
- ✓A failed preflight is a configuration mismatch, not proof the API is safe.
The browser console says a request was blocked by CORS. Someone sets Access-Control-Allow-Origin to a star, the error disappears, and the API is described as fixed. The browser is now willing to show the response to any website. The API learned nothing about the caller.
The Fetch standard defines CORS so that a script on one origin cannot quietly read a response from another. The browser sends the request, then withholds the response from the script unless the server opts in with the right headers. A phone app, a backend job, or curl does not perform that check. If your threat model is "only our website may call this," CORS is the wrong control. Authentication and authorization are the control.
The decisions that actually matter
- List the origins that may read responses. Prefer an explicit list over a reflection of whatever Origin arrived.
- If the browser must send cookies, set the credentials header and name the origin. The star and credentials together are rejected by browsers for a reason: they would expose a credentialed response to every site.
- Allow only the methods and headers you use. A preflight exists so the browser can ask before a request that is not a simple one.
- Authenticate the call anyway. An allowed origin can be a malicious page a user is logged into if your cookie is sent and your API does not check a token bound to your own site.
- Do not treat a CORS error as an outage of the API. The API may have returned 200. The browser hid it.
Illustrative scenario
This scenario is illustrative. A dashboard on app.example.com calls api.example.com with a cookie. The API allows that one origin and requires a session. A different site cannot read the JSON, because the browser withholds it. A script on a server can still call the API if it has a stolen session cookie. CORS did not stop that. Session expiry, cookie scope, and a check that the caller is the user did the work CORS cannot do. The same split applies when a model tool calls the API: the tool is not a browser, so permission boundaries have to be enforced on the server.
Checklist
- Write down the origins that should read this API from a browser.
- Refuse to reflect an arbitrary Origin when cookies are in use.
- Keep authentication on every route that returns private data.
- Log the status you actually returned. A browser-reported CORS failure is not the status.
- Review the list when a new frontend domain is added. Do not leave a wildcard from a local prototype.
Questions that usually come next
Does CORS protect a public API?
It protects a browser user from a random site reading a credentialed response. A public API that returns data to anyone is public to non-browser clients regardless of the header. Rate limits and authentication still apply if the data is not meant to be public.
Should we disable CORS in development by allowing every origin?
Allow your local origin explicitly. A wildcard that ships because the development setting was copied into production is a common way private responses become readable by other sites.
Direct answers
Does CORS protect a public API?
It limits which websites can read a response in a browser. Non-browser clients are not limited by it. Authenticate anything that is not public.
Should development allow every origin?
Allow the local origin you actually use. A wildcard copied into production lets other sites read credentialed responses.
References & Prior Art
Fetch Standard: CORS protocol
WHATWG • WHATWG (2026)
Barath
Product EngineerBarath builds production internal tools, double-entry financial ledgers, audit trail integrity, and supervised engineering workflows at Vasiva.