Introduction
Cross‑Origin Resource Sharing (CORS) errors are one of the most common roadblocks when building APIs with Node.js. In this guide we’ll walk through the root causes, quick fixes, and robust solutions so you can eliminate those frustrating browser warnings in minutes.
Why CORS Errors Appear
Browsers enforce the Same‑Origin Policy. When a web page at https://example.com tries to fetch data from http://api.myservice.local, the browser checks the response headers for Access‑Control-Allow-Origin. If the header is missing or mismatched, the request is blocked and you see:
Access to fetch at 'http://api.myservice.local/data' from origin 'https://example.com' has been blocked by CORS policy
1️⃣ Quick Fix: Use the cors Middleware
The easiest way to enable CORS in an Express app is to add the official cors package.
const express = require('express');
const cors = require('cors');
const app = express();
// Enable CORS for all routes – you can customise the options object
app.use(cors({
origin: '*', // <- replace '*' with specific domains in production
methods: ['GET','POST','PUT','DELETE'],
credentials: true
}));
app.get('/api/hello', (req, res) => {
res.json({msg: 'CORS works!'});
});
app.listen(3000, () => console.log('Server running on http://localhost:3000'));
Tip: For tighter security, replace
origin: '*'with an array of trusted domains.
2️⃣ Manual Header Approach (No Extra Dependency)
If you prefer not to add a library, set the headers yourself.
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*'); // <-- change '*' in prod
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// Handle pre‑flight requests
if (req.method === 'OPTIONS') {
return res.sendStatus(204);
}
next();
});
This works for simple APIs but can become cumbersome as the list of allowed methods or headers grows.
3️⃣ Advanced: Proxy Requests Through Nginx or a Node.js Proxy
When you cannot modify the upstream service (e.g., third‑party API), proxy the request so the browser only talks to your same‑origin server.
const { createProxyMiddleware } = require('http-proxy-middleware');
app.use('/external', createProxyMiddleware({
target: 'https://thirdparty.com',
changeOrigin: true,
pathRewrite: {'^/external': ''},
onProxyRes(proxyRes) {
// Inject CORS headers on the fly
proxyRes.headers['Access-Control-Allow-Origin'] = '*';
}
}));
Now a front‑end call to /external/data will be routed through your Node server, bypassing the original CORS restrictions.
4️⃣ Step‑by‑Step Troubleshooting Checklist
- Check the response headers – Use Chrome DevTools → Network → Response Headers.
-
Verify the request method – OPTIONS pre‑flight must return
204or200with proper headers. -
Confirm the origin – The value of
Access-Control-Allow-Originmust match the request’sOriginheader (or be*). -
Look for middleware ordering issues –
app.use(cors())must be placed before route definitions. - Inspect server logs – Some frameworks silently drop headers on errors.
- Test with a curl command to see raw headers:
curl -i -X OPTIONS http://localhost:3000/api/hello -H "Origin: https://example.com" -H "Access-Control-Request-Method: GET"
5️⃣ Deploy‑Ready Configuration
Below is a production‑ready Express setup that:
- Whitelists specific domains.
- Handles credentials securely.
- Logs CORS activity for audit.
const express = require('express');
const cors = require('cors');
const morgan = require('morgan');
const whitelist = ['https://app.example.com', 'https://admin.example.com'];
const corsOptions = {
origin: (origin, callback) => {
if (!origin || whitelist.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true,
methods: ['GET','POST','PUT','DELETE','OPTIONS'],
allowedHeaders: ['Content-Type','Authorization']
};
const app = express();
app.use(morgan('combined'));
app.use(cors(corsOptions));
app.get('/api/status', (req, res) => {
res.json({status: 'ok'});
});
app.listen(8080, () => console.log('Production server listening on :8080'));
Conclusion
CORS errors are not a dead‑end; they’re a signal that your API needs clearer communication with the browser. By leveraging the cors middleware, setting headers manually, or proxying requests, you can resolve the issue quickly and keep your development pipeline moving.
Ready to accelerate your fix? Download the pre‑configured script here, or explore the full toolbox with Get the complete patch tool. For a deeper dive, Access the full repository fix and integrate it into your CI/CD workflow.
Top comments (0)