TL;DR
CORS is a browser security feature that blocks cross-origin requests unless the server explicitly allows them. Fix it by setting the correct Access-Control-Allow-Origin header on your server, not by disabling the check.
You are building a web app. Your frontend runs on localhost:3000. Your API runs on localhost:8000. You make a fetch request, and the browser throws an error: 'Access to fetch at localhost:8000 from origin localhost:3000 has been blocked by CORS policy.'
This error confuses developers because the request looks fine, it worked in Postman, and nothing seems obviously wrong. The issue is not your code -- it is the browser protecting you from a security attack you have never heard of.
What CORS Actually Is
CORS stands for Cross-Origin Resource Sharing. To understand it, you first need to understand the Same-Origin Policy.
Browsers enforce a rule that JavaScript on one origin (protocol + domain + port) cannot read responses from a different origin. localhost:3000 and localhost:8000 are different origins because the ports differ. yourapp.com and api.yourapp.com are different origins because the subdomains differ.
The Same-Origin Policy exists to prevent a specific attack: if you visit a malicious website, it should not be able to use your browser to make authenticated requests to your bank's API and read the response. Your browser has your bank's session cookie. Without the Same-Origin Policy, any page you visit could exploit that.
CORS is the mechanism that lets servers selectively relax this restriction. A server can say: 'I trust requests from yourapp.com and will allow cross-origin access from that domain.'
How the Browser Checks CORS
For simple GET and POST requests with standard headers, the browser makes the request and then checks the response headers. If the server sends back Access-Control-Allow-Origin: * or Access-Control-Allow-Origin: https://yourapp.com, the browser allows the response to be read by the JavaScript that made the request.
For requests that modify data (PUT, DELETE, PATCH) or use custom headers, the browser first sends a preflight OPTIONS request to ask the server whether the actual request is allowed. The server must respond with the appropriate CORS headers or the browser will block the real request.
How to Fix CORS Properly
The fix is always on the server side. The browser is doing its job correctly and cannot be overridden by client code.
In Django (with django-cors-headers):
Install django-cors-headers, add it to INSTALLED_APPS and MIDDLEWARE, then set:
CORS_ALLOWED_ORIGINS = [
'https://yourfrontend.com',
]
In Express (Node.js):
const cors = require('cors');
app.use(cors({ origin: 'https://yourfrontend.com' }));
In Nginx:
add_header 'Access-Control-Allow-Origin' 'https://yourfrontend.com';
What Not to Do
The most common mistake is setting Access-Control-Allow-Origin: * on an API that uses cookies or session authentication. Wildcard origins cannot be combined with Access-Control-Allow-Credentials: true. If you need credentials, you must specify the exact origin.
The second most common mistake is installing a browser extension that disables CORS checks for development. This works locally but gives you a false sense that your API is correctly configured. Ship it and users will hit CORS errors immediately.
The third mistake is proxying in development without configuring production. Many frontend dev servers (Create React App, Vite) support a proxy setting that avoids CORS locally. This does not exist in production and should be replaced with proper server-side CORS configuration.
CORS Is Not a Security Feature for Your API
CORS only affects browser clients. Curl, Postman, server-to-server requests, and mobile apps are not subject to CORS. If your API has sensitive data, it must have authentication and authorization -- CORS alone does not protect it. A malicious actor will simply use a tool that is not a browser.
Khodor Ghalayini
Engineer · AI Builder · Cybersecurity Practitioner
Engineer with 10+ years in systems and project management. I build AI-powered tools to help people work smarter — starting with the security and productivity problems I've personally run into. More about me →