Access to fetch at 'http://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.
- Server doesn't send CORS headers — most common cause
- Wrong origin in allowed list — typo or mismatch
- Preflight OPTIONS not handled — missing OPTIONS handler
- Credentials + wildcard —
credentials: includewith*origin is invalid
CORS errors only happen in browsers. The server must explicitly allow the frontend's origin.
// Node.js/Express — add CORS headers
const cors = require('cors');
app.use(cors({
origin: 'http://localhost:3000', // your frontend URL
credentials: true // allow cookies/auth
}));const cors = require('cors');
// Allow all origins (development only!)
app.use(cors());
// Allow specific origins (production)
app.use(cors({
origin: ['https://yourdomain.com', 'http://localhost:3000'],
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
}));
// Handle preflight for all routes
app.options('*', cors());app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type,Authorization');
res.header('Access-Control-Allow-Credentials', 'true');
if (req.method === 'OPTIONS') return res.sendStatus(200);
next();
});// vite.config.js
export default {
server: {
proxy: {
'/api': {
target: 'http://api.example.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
},
};
// webpack devServer:
devServer: {
proxy: { '/api': 'http://api.example.com' }
}- Never use
Access-Control-Allow-Origin: *withcredentials: true - In production, whitelist only known trusted origins
- Consider using a same-domain API to avoid CORS entirely