If your browser console shows “blocked by CORS policy,” your code is usually fine. The browser is doing its job. This article explains what CORS actually is, why the error appears, and how to fix it on the server side without disabling security. By the end you will be able to diagnose most CORS failures in minutes.
What CORS Really Is
CORS stands for Cross-Origin Resource Sharing. An origin is the combination of scheme, host, and port, for example https://app.example.com. When JavaScript on one origin tries to read a response from a different origin, the browser enforces the Same-Origin Policy and asks the server for permission through CORS headers.
The key point most people miss: CORS is enforced by the browser, not the server. The server still receives the request and can still run. The browser simply refuses to hand the response back to your JavaScript unless the correct headers are present. That is why the same API call works in a tool like curl or Postman but fails in the browser.
Simple vs Preflighted Requests
Some requests are sent directly. Others trigger a preflight, an automatic OPTIONS request the browser sends first to ask if the real request is allowed. A request is preflighted when it uses methods like PUT or DELETE, custom headers, or a JSON content type. If your OPTIONS response is not handled correctly, the real request never happens.
Why the Error Appears
The error means the server did not return a matching Access-Control-Allow-Origin header, or the preflight was not answered properly. Common causes:
- The server sends no CORS headers at all.
- The allowed origin does not exactly match the requesting origin, including scheme and port.
- The request sends credentials, but the server uses a wildcard origin, which browsers forbid together.
- The OPTIONS preflight returns a 404 or 500 because no route handles it.
A Real Scenario
A team built a React app on http://localhost:3000 calling an API on http://localhost:8080. GET requests worked, but POST with a JSON body failed. The cause was the preflight. Their framework only registered POST, so the automatic OPTIONS request returned 404. Adding a handler that answers OPTIONS with Access-Control-Allow-Methods and Access-Control-Allow-Headers fixed it immediately. Nothing in the frontend changed.
How to Fix It
Fix CORS on the server that owns the resource. Set headers that reflect exactly what the browser needs:
| Access-Control-Allow-Origin | The specific requesting origin, or a known list. Avoid blind wildcards in production. |
| Access-Control-Allow-Methods | The HTTP methods you permit, such as GET, POST, PUT, DELETE. |
| Access-Control-Allow-Headers | Custom headers the client sends, such as Content-Type or Authorization. |
| Access-Control-Allow-Credentials | Set to true only if cookies or auth are used, and never with a wildcard origin. |
Common Mistakes and How to Fix Them
Trying to fix it in frontend code. Adding headers to your fetch request does nothing. CORS headers must come from the responding server. Fix: change the server or its proxy.
Using a wildcard with credentials. A wildcard origin combined with credentials is rejected by browsers. Fix: echo back the specific origin instead of using an asterisk.
Forgetting the preflight. If GET works but POST fails, your OPTIONS route is missing. Fix: handle OPTIONS and return a 204 with the allow headers.
Confusing CORS with a network error. A CORS block and a server crash can look similar. Fix: check the Network tab; if the request reached the server and returned a status, it is a CORS header problem.
Action Checklist
- Open the Network tab and confirm the request actually reached the server.
- Compare the requesting origin and the allowed origin character by character.
- Check whether an OPTIONS preflight was sent and what it returned.
- Add the four core CORS headers on the API server or reverse proxy.
- If using cookies, set credentials to true and drop the wildcard origin.
- Retest in the browser, not just in curl.
Conclusion
CORS is a browser safety feature, not a bug. Once you understand that the fix belongs on the server and that preflights must be answered, most errors become quick to resolve. Next step: reproduce your failing request in the Network tab and identify whether it is a missing header or an unhandled preflight.
FAQ
Can I disable CORS in the browser?
You can launch a browser with security flags off for local testing, but never rely on this. It only affects your machine and leaves the real problem unsolved. Fix the server instead.
Why does it work in Postman but not the browser?
Postman and curl do not enforce the Same-Origin Policy. Only browsers do. A passing request in Postman confirms the server works, not that CORS is configured.
Is CORS a security feature I should keep?
Yes. It prevents malicious sites from silently reading data from other origins using a logged-in user’s session. Configure it narrowly rather than turning it off.
Should I just allow all origins?
Only for truly public, non-credentialed APIs. For anything involving authentication or private data, allow a specific list of trusted origins.
References
MDN Web Docs, Cross-Origin Resource Sharing (CORS) documentation, a widely used and authoritative reference maintained by Mozilla.