CORS (Cross-Origin Resource Sharing) is a browser security mechanism that controls whether a web page running at one origin is allowed to request resources from a different origin.
TL;DR CORS is enforced by browsers, not servers. When JavaScript at
app.example.comfetches data fromapi.other.com, the browser checks whether the API server explicitly permits this cross-origin request by examining HTTP response headers — primarilyAccess-Control-Allow-Origin. If the header is missing or doesn’t match, the browser blocks the response, even though the server successfully processed it. CORS errors are client-side blocks, not server-side failures. The fix is always adding the correct response headers on the server (or edge) that receives the request.
What is CORS?
CORS (Cross-Origin Resource Sharing) is a W3C standard implemented by all modern browsers. It extends the same-origin policy — the rule that a web page can only access resources from the exact same origin (protocol + domain + port) — by allowing servers to explicitly declare which other origins are permitted to access their resources.
An origin is defined by three components:
- Protocol —
https://vshttp:// - Domain —
example.comvsapi.example.com - Port —
:443vs:3000
Two URLs have the same origin only if all three match exactly. https://app.example.com and https://api.example.com are different origins because the subdomain differs.
Why CORS exists
Without the same-origin policy, any malicious website could use JavaScript to make requests to your bank, email, or any authenticated service — and the browser would send your session cookies automatically. The browser would then receive and expose the response to the attacker’s script.
The same-origin policy prevents this by blocking cross-origin reads. CORS then provides a controlled way for servers to opt in to cross-origin sharing — selectively and explicitly.
How CORS works
Simple requests
A simple request is a cross-origin request that meets all of these conditions:
- Method is
GET,POST, orHEAD - Headers are only
Accept,Accept-Language,Content-Language, orContent-Type(with valueapplication/x-www-form-urlencoded,multipart/form-data, ortext/plain)
For simple requests, the browser sends the request directly and includes an Origin header. The server must respond with Access-Control-Allow-Origin matching the request origin. If it doesn’t, the browser blocks the response from reaching JavaScript.
Request:GET /data HTTP/1.1Origin: https://app.example.com
Response:Access-Control-Allow-Origin: https://app.example.comPreflight requests
For requests that don’t meet the simple request criteria — such as PUT, DELETE, PATCH, or requests with custom headers like Authorization — the browser first sends a preflight request using the OPTIONS method.
OPTIONS /data HTTP/1.1Origin: https://app.example.comAccess-Control-Request-Method: PUTAccess-Control-Request-Headers: Authorization, Content-TypeThe server must respond to the preflight with the appropriate CORS headers before the browser sends the actual request:
HTTP/1.1 204 No ContentAccess-Control-Allow-Origin: https://app.example.comAccess-Control-Allow-Methods: GET, POST, PUT, DELETEAccess-Control-Allow-Headers: Authorization, Content-TypeAccess-Control-Max-Age: 86400If the preflight fails, the browser never sends the actual request.
CORS response headers
| Header | Purpose | Example value |
|---|---|---|
Access-Control-Allow-Origin | Specifies which origin(s) may access the resource | https://app.example.com or * |
Access-Control-Allow-Methods | Allowed HTTP methods for cross-origin requests | GET, POST, PUT, DELETE |
Access-Control-Allow-Headers | Allowed request headers | Authorization, Content-Type |
Access-Control-Allow-Credentials | Whether cookies/credentials are included | true |
Access-Control-Max-Age | How long (seconds) the preflight result can be cached | 86400 |
Access-Control-Expose-Headers | Which response headers JavaScript can read | X-Request-ID |
Critical rule: You cannot use Access-Control-Allow-Origin: * together with Access-Control-Allow-Credentials: true. Browsers reject this combination. You must specify the exact origin when credentials are involved.
Common CORS errors and fixes
| Error message | Cause | Fix |
|---|---|---|
No 'Access-Control-Allow-Origin' header is present | Server doesn’t return the CORS header | Add Access-Control-Allow-Origin to the response |
The value of 'Access-Control-Allow-Origin' does not equal the supplied origin | Header value doesn’t match the requesting origin | Dynamically reflect the request Origin or list all allowed origins |
Response to preflight request doesn't pass access control check | Preflight OPTIONS request not handled | Add OPTIONS handler that returns proper CORS headers |
Credential flag is true but Access-Control-Allow-Credentials is not true | Credentials sent but server didn’t permit them | Add Access-Control-Allow-Credentials: true and specify exact origin |
Method PUT is not allowed | Method missing from Access-Control-Allow-Methods | Add the required method to the allowed methods header |
Request header 'Authorization' is not allowed | Custom header not listed in Access-Control-Allow-Headers | Add the header to Access-Control-Allow-Headers |
CORS security risks
Wildcard with credentials
Using Access-Control-Allow-Origin: * is safe for public APIs that don’t use cookies or session tokens. Never combine * with Access-Control-Allow-Credentials: true — it exposes authenticated data to any origin.
Reflecting the Origin header without validation
Some implementations blindly reflect the Origin request header back as Access-Control-Allow-Origin. If you do this without validating against an allowlist, you allow any origin to access your API. Always validate the Origin value against a whitelist before reflecting it.
Null origin
The Origin: null value is sent by browsers for requests from file:// URLs or sandboxed iframes. Never allowlist null as a permitted origin — it can be exploited.
Frequently asked questions
What is a CORS error? A CORS error is a browser-enforced block on a cross-origin HTTP response. It means JavaScript at one origin tried to read a response from a different origin, but the server’s response didn’t include the headers granting permission. The request itself reached the server — the browser just blocked the response from being accessible to the script.
Does CORS apply to server-to-server requests? No. CORS is enforced by browsers only. When your backend server calls another API, there is no CORS enforcement — the call goes through regardless. CORS only applies when JavaScript running in a browser makes a cross-origin request.
What is the difference between CORS and the same-origin policy? The same-origin policy is the default browser security rule that blocks cross-origin reads. CORS is the mechanism that allows servers to selectively relax that restriction by returning specific HTTP headers. CORS doesn’t bypass the same-origin policy — it provides a standardized way for servers to opt in to cross-origin access.
Can I disable CORS? You cannot disable CORS in browsers — it is enforced at the browser level. What you can do is configure your server to return the correct CORS headers that permit your specific cross-origin requests. Browser extensions that “disable CORS” only work by intercepting responses and injecting the missing headers client-side.
What does Access-Control-Allow-Origin: * mean? It means any origin is allowed to read the response. This is appropriate for fully public APIs (no authentication, no cookies). Never use * for APIs that require authentication or access to user data.
What is a preflight request? A preflight request is an automatic OPTIONS request that the browser sends before certain cross-origin requests to ask the server what it permits. The server must respond with CORS headers approving the method, headers, and origin before the browser sends the actual request. Preflight responses can be cached using Access-Control-Max-Age.
How do I fix CORS errors in development? In development, the most common approach is to configure your local API server to return Access-Control-Allow-Origin: http://localhost:3000 (your frontend dev server URL). Do not use a browser extension to bypass CORS in development — it hides real problems that will appear in production.
Can a CDN or edge handle CORS for me? Yes. You can configure CORS headers at the edge — adding Access-Control-Allow-Origin and other headers to responses before they reach the browser, without modifying the origin server. This is useful for third-party APIs you don’t control, or for centralizing CORS policy across multiple origins.