
What is CORS and Why is My JavaScript fetch Blocked?

CORS is one of those front‑end problems that makes beginners feel like the browser is being deliberately rude. The request looks valid. The endpoint exists. The server may even respond when you test it elsewhere. But the browser still blocks the call and fills the console with warnings about cross‑origin requests.
That is frustrating mainly because it looks like a network problem when it is really a browser security rule.
Once you understand that, CORS stops feeling random. It is still annoying, but at least it becomes predictable.
CORS Sits on Top of the Same‑Origin Policy
To understand CORS, you need the same‑origin policy first.
Browsers do not let any page read data from any other origin by default. That would be a security disaster. If it were allowed, a malicious website could quietly make requests on your behalf to other sites and read back the results too easily.
An origin is defined by the combination of:
- protocol
- hostname
- port
So these count as different origins:
https://example.comhttp://example.comhttps://api.example.comhttps://example.com:8080
If your front‑end code on one origin tries to read a response from another origin, the browser checks whether that cross‑origin read is allowed.
CORS is the mechanism for that permission.
What CORS Actually Means
CORS stands for Cross‑Origin Resource Sharing.
In practical terms, it is a system of HTTP headers that let a server say, "yes, this browser page from that other origin is allowed to read my response".
If the server does not grant permission in the way the browser expects, the browser blocks access to the response from JavaScript.
That last part matters. A CORS problem is not just "the request failed on the wire". Quite often the request really did go out and the server really did respond. The browser is simply refusing to expose the response to your front‑end code because the cross‑origin rules were not satisfied.
A Basic Example
Imagine a page running on:
https://shop.example.comand your front‑end code tries to fetch data from:
https://api.example.net/productsconst loadProducts = async (): Promise<void> => { const response = await fetch('https://api.example.net/products'); const products = await response.json(); console.log(products);};That is a cross‑origin request because the hostname differs. The browser will only let your code read the response if the API replies with the right CORS headers.
The Server Has to Opt in
This is the part many beginners need stated very plainly:
front‑end JavaScript does not get to decide CORS by itself.
The server you are calling must return headers that permit the cross‑origin request. A common example is:
Access-Control-Allow-Origin: https://shop.example.comor sometimes:
Access-Control-Allow-Origin: *No surprise, then, that CORS often feels annoying from the front‑end side. You can trigger the request, but you cannot simply override the browser's security model from your JavaScript.
Why It Sometimes Works in Postman or Curl
This confuses a lot of people.
You test the endpoint in Postman or cURL and it works perfectly, so you assume the browser must be wrong. Usually it is not.
The key point is that CORS is a browser security feature. Tools like Postman and cURL are not browsers, so they do not enforce the same‑origin policy in the same way.
That means an endpoint can respond successfully in Postman and still fail from front‑end code because the browser is applying rules those other tools do not care about.
If you remember nothing else about CORS, remember this:
working in Postman does not prove that browser JavaScript will be allowed to read the response.
Some Requests Trigger a Preflight Check
Not every cross‑origin request is treated the same way.
Some simple requests can be sent directly and then checked against the response headers. Others trigger a preflight request first. This is usually an OPTIONS request the browser sends to ask the server which methods, headers, or credentials are allowed.
You are more likely to hit a preflight when you:
- use methods such as
PUT,PATCH, orDELETE - send custom headers
- send content types outside the simpler allowed set
That explains why a request can look fine until one extra header turns it into a CORS problem. The browser is no longer only checking the final response. It may also be checking whether the server handled the preflight correctly.
What Front‑End Developers Can Fix
This is where being precise helps.
Front‑end developers usually can:
- call the correct endpoint
- avoid unnecessary custom headers
- avoid sending credentials unless genuinely needed
- work with a same‑origin back end or proxy
- give the back‑end team the exact browser error and request details
Front‑end developers usually cannot:
- add
Access‑Control‑Allow‑Originfrom browser code - force the browser to ignore the same‑origin policy
- fix a server that refuses the required cross‑origin headers
In reality, many CORS problems are integration issues between the front end and back end rather than purely front‑end bugs.
Credentials Make the Rules Stricter
If you include cookies or authentication information in a cross‑origin request, the rules become tighter.
For example:
await fetch('https://api.example.net/account', { credentials: 'include',});In cases like that, wildcard CORS settings are often not enough. The server has to be more explicit about which origin is allowed, and it has to allow credentials properly as well.
Beginners often get stuck here because they add credentials to a request without realising they have changed the browser's expectations about the response headers.
The Quickest Way to Debug a CORS Issue
When I hit a CORS problem, I usually check these things first:
- What is the exact origin of the page making the request?
- What is the exact origin of the API endpoint?
- Is the browser error about the final response or a preflight request?
- Are custom headers or credentials involved?
- Does the server return the expected
Access‑Control‑Allow‑*headers?
That is usually enough to separate "front‑end request shape problem" from "server permissions problem".
It is also worth checking the browser network panel instead of only reading the console. The network view often shows whether the preflight failed, which headers were sent, and what the server returned.
CORS is Not the Same Thing as Authentication
This is another beginner mix‑up worth avoiding.
CORS does not decide whether a user is authorised to access data. It decides whether a browser page from one origin is allowed to read a response from another origin.
You can have:
- a request that passes authentication but fails CORS
- a request that passes CORS but fails authentication
They are different layers of the problem.
Wrapping up
CORS is the browser's way of enforcing cross‑origin read permissions. It exists because browsers should not let any website read responses from any other website by default. Once you understand that the server must opt in with the right headers, the problem becomes much easier to reason about. Frustrating, yes. Random, no.
Key Takeaways
- CORS is a browser security mechanism built on top of the same‑origin policy.
- Cross‑origin requests are allowed only when the server returns the right headers.
- Front‑end JavaScript cannot simply switch CORS off from the browser.
- Postman and cURL can succeed even when browser code is blocked, because they are not enforcing browser CORS rules.
- Custom headers, non‑simple methods, and credentials often make CORS stricter by triggering preflight checks.
Once you stop treating CORS as a vague fetch failure and start treating it as an explicit browser permission check, the errors become much easier to diagnose.
Related Articles

Creating and Dispatching Custom Events in JavaScript. 
Event Delegation in JavaScript. Event Delegation in JavaScript
Handling Click Events in JavaScript. Handling Click Events in JavaScript
DOM Traversal: closest() in Vanilla JavaScript and jQuery. DOM Traversal:
closest()in Vanilla JavaScript and jQuery
Angular Standalone Components: Do We Still Need Modules? Angular Standalone Components: Do We Still Need Modules?

Null and undefined in JavaScript. nullandundefinedin JavaScript
Best Practices for Cross‑Browser Compatibility. Best Practices for Cross‑Browser Compatibility

3Sum Closest in JavaScript: Sorting and Two Pointers. 3Sum Closest in JavaScript: Sorting and Two Pointers

Preventing and Debugging Memory Leaks in React. Preventing and Debugging Memory Leaks in React

Solving the LeetCode 'Binary Tree Zigzag Level Order Traversal' Problem. Solving the LeetCode 'Binary Tree Zigzag Level Order Traversal' Problem

Understanding Event Loop and Concurrency in JavaScript. Understanding Event Loop and Concurrency in JavaScript

10 Essential SEO Tips for Front‑End Developers. 10 Essential SEO Tips for Front‑End Developers