
Introduction
When I first started working with APIs, I kept running into this mysterious error in my browser console:
Access to fetch at https://api.example.com/data from origin http://localhost:3000 has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
At first, I thought my code was broken. I spent hours debugging my fetch requests, changing headers, even questioning my sanity.
Turns out, it wasn’t a bug in my code—it was CORS.
CORS, or Cross-Origin Resource Sharing, is a browser security mechanism that controls how web pages can request resources from a different domain. It prevents malicious websites from sneaking around and accessing your private APIs or data without permission.
Let’s demystify it.
What I Thought About CORS
At first, I thought CORS was just a “browser problem”—something I could ignore or patch with random headers I found online. Tutorials often suggested adding:
res.setHeader("Access-Control-Allow-Origin", "*");
And that would magically fix everything. But this approach is risky in production. It basically says: “Hey browser, allow anyone, anywhere, to access this API.” Not ideal for sensitive data.
I realized that to really understand CORS, I needed to know why browsers enforce it, not just how to bypass it.
My New Understanding of CORS
CORS exists because browsers follow the Same-Origin Policy (SOP). This policy restricts web pages from making requests to a different domain than the one that served the page.
- Origin is defined by protocol + domain + port.
- Example:
http://localhost:3000andhttp://example.comare different origins.
CORS allows servers to tell browsers: “It’s okay for this page from another origin to access my resources.”
Here are the main pieces I now understand:
-
Simple Requests: GET, POST, or HEAD requests with standard headers. Browser sends the request directly and checks the response headers for permission.
-
Preflight Requests: For non-simple requests (like PUT, DELETE, or custom headers), browsers send an OPTIONS request first to ask the server if the actual request is allowed.
-
CORS Headers:
Access-Control-Allow-Origin: Specifies which origin(s) can access the resource.Access-Control-Allow-Methods: Which HTTP methods are allowed (GET, POST, etc.).Access-Control-Allow-Headers: Which custom headers can be used.Access-Control-Allow-Credentials: Whether cookies or authentication info can be sent.
-
Credentials & Cookies: Browsers block credentials by default. If your API requires cookies or auth headers, the server must explicitly allow them with Access-Control-Allow-Credentials: true and cannot use * for the origin.
Example Scenario
Suppose your frontend runs at http://localhost:3000 and your backend API is at http://api.example.com.
A simple CORS setup in Node.js/Express would look like:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({
origin: 'http://localhost:3000',
methods: ['GET', 'POST'],
credentials: true
}));
app.get('/data', (req, res) => {
res.json({ message: 'Hello from API!' });
});
app.listen(4000, () => console.log('API running on port 4000'));
Now, your frontend can safely make requests without running into CORS errors.
Why CORS Matters
Understanding CORS is more than just fixing errors. It’s about web security:
- Prevents Cross-Site Request Forgery (CSRF) attacks.
- Ensures data privacy across different origins.
- Forces developers to think about who can access APIs.
Ignoring it might work in development with
*, but in production, proper CORS policies are crucial.
Resources That Helped Me
-
MDN Web Docs – CORS Clear explanation of headers, preflight requests, and real-world examples.
-
Web.dev – CORS Visual guides and diagrams that explain request flow between browser and server.
-
Express.js Documentation – CORS Middleware Quick way to implement secure and flexible CORS policies in Node.js.
Conclusion
CORS may seem annoying at first—blocking requests left and right—but it’s a security feature, not a bug. Once you understand origins, headers, and preflight requests, you can configure APIs safely and avoid random browser errors.
Think of CORS like a bouncer at a club: only letting trusted guests in, keeping your data secure, and preventing chaos.
Next steps: in upcoming posts, I’ll explore common CORS mistakes, debugging tips, and real-world scenarios in modern web applications.
CORS isn’t just a hurdle—it’s a fundamental part of how the web stays safe.