The simple version
When you build a web app that talks to another website (for example, a React front‑end asking a Django API for data), you might see a browser error that looks like this in the console:
Access‑Control‑Allow‑Origin: null
Access‑Control‑Error: Cross‑Origin Request Blocked
That’s a CORS error – short for Cross‑Origin Resource Sharing.
It happens because browsers protect pages from asking other sites for data unless the other site explicitly says it’s OK. Think of it as a polite “no” that the browser automatically gives you when you try to do something that could be unsafe.
Below we break it down into bite‑size bits, show why it matters, and give you quick ways to fix it.
Why the Browser Blocks Cross‑Origin Requests
Every web page has an origin – the combination of protocol (http/https), domain, and port.
The Same‑Origin Policy says: “A page can only freely talk to resources that share its exact origin.”
If your page at http://localhost:3000 tries to fetch https://api.example.com/data, the origins differ, so the browser blocks the request unless the server says it’s fine.
The policy is a security blanket that keeps malicious scripts from stealing data across sites.
How CORS Works: The Handshake
- The Request – Your page sends a request to a different origin.
- Preflight (optional) – For “non‑simple” requests (e.g., using
PUTor custom headers), the browser first sends anOPTIONSrequest. - Server Response – The server must reply with an
Access-Control-Allow-Originheader that matches the requesting origin (or*for any origin). - Success or Block – If the header is present and matches, the browser lets the real response through. If not, it blocks the data and shows the CORS error.
Analogy: Think of the browser as a bouncer at a club. Your page is the guest, and the server is the club. If the bouncer (browser) doesn’t see a valid ID (header), they won’t let you in.
Common Causes of CORS Errors
| Cause | What it looks like | Fix |
|---|---|---|
| Missing header | No Access-Control-Allow-Origin in the response |
Add it on the server |
| Wrong value | Header says http://example.com but request comes from http://localhost:3000 |
Use a dynamic value or * |
| Preflight mismatch | Server doesn’t answer the OPTIONS request or returns 404 |
Handle OPTIONS on the server |
| Credentials | Request uses withCredentials:true but header is * |
Set a specific origin and Access-Control-Allow-Credentials:true |
| HTTPS/HTTP mix | Request from https:// to http:// |
Use the same scheme (prefer HTTPS) |
Fixing CORS Errors
1. Tell the Server to Allow the Origin
If you control the API, add the header. In Express.js:
// server.js
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({ origin: 'http://localhost:3000' })); // or origin: '*'
app.get('/data', (req, res) => {
res.json({ message: 'Hello, world!' });
});
app.listen(4000, () => console.log('API running on 4000'));
The cors middleware automatically handles preflight requests for you.
2. Use a Proxy for Development
If you can’t change the server, route your API calls through a local proxy that injects the header.
- Create React App:
npm run startautomatically proxies/apitohttp://localhost:4000. - Node Proxy: Use
http-proxy-middleware.
3. Enable CORS on the Server Manually
If you’re using Flask, add:
from flask import Flask, jsonify
from flask_cors import CORS
app = Flask(__name__)
CORS(app, origins="http://localhost:3000")
@app.route("/data")
def data():
return jsonify(message="Hello, world!")
4. Check the Response with curl
curl -i http://localhost:4000/data
Look for the Access-Control-Allow-Origin header. If it’s missing, the server isn’t configured correctly.
Quick Code Example: A Minimal CORS‑Enabled API
// simpleServer.js
const http = require('http');
const server = http.createServer((req, res) => {
// Allow all origins – only for demo purposes
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Content-Type', 'application/json');
if (req.method === 'OPTIONS') {
// Preflight response
res.writeHead(204);
return res.end();
}
// Real request
res.end(JSON.stringify({ hello: 'world' }));
});
server.listen(4000, () => console.log('Listening on http://localhost:4000'));
Run it with node simpleServer.js and hit http://localhost:4000 from your front‑end. The browser will now allow the data.
What to try next
Test a CORS‑enabled endpoint
Usefetch('http://localhost:4000/data')from a local HTML file. If you see the JSON, you’ve fixed CORS.Inspect Network in DevTools
Open the browser’s Network tab, click the request, and look at theResponse Headers. VerifyAccess-Control-Allow-Originis present.Add CORS to a Flask API
Create a tiny Flask app, installflask-cors, and expose an endpoint. Practice toggling theoriginsargument between*and a specific URL.
Happy coding, and may your cross‑origin requests flow smoothly!