How to Fix CORS Errors
CORS errors occur when your frontend tries to make requests to a different domain than where it is hosted. The browser blocks these requests for security. This guide explains how CORS works and how to configure it correctly without compromising security.
Find security issues automatically before attackers do.
Follow These Steps
Understand why CORS errors occur
CORS is a browser security feature that blocks requests from one origin to another unless the server explicitly allows it.
// This fails if your API does not allow your frontend origin:
// Frontend: https://myapp.com
// API: https://api.myapp.com
fetch('https://api.myapp.com/data') // CORS error!Configure CORS on your API server
Set the Access-Control-Allow-Origin header to your frontend domain.
// Express.js
import cors from 'cors'
app.use(cors({
origin: 'https://myapp.com', // Your frontend domain
methods: ['GET', 'POST', 'PUT', 'DELETE'],
credentials: true, // If using cookies/auth headers
maxAge: 86400 // Cache preflight for 24 hours
}))Handle multiple allowed origins
If your API serves multiple frontends, dynamically set the origin.
const allowedOrigins = [
'https://myapp.com',
'https://staging.myapp.com',
'http://localhost:3000'
]
app.use(cors({
origin: (origin, callback) => {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
},
credentials: true
}))Handle preflight requests
Browsers send an OPTIONS request before certain cross-origin requests. Your server must respond correctly.
// Express handles this automatically with the cors middleware
// For manual configuration:
app.options('*', (req, res) => {
res.header('Access-Control-Allow-Origin', 'https://myapp.com')
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE')
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization')
res.header('Access-Control-Max-Age', '86400')
res.sendStatus(204)
})Use a proxy for development
Instead of allowing localhost in CORS, use a development proxy.
// next.config.js (Next.js)
module.exports = {
async rewrites() {
return [{
source: '/api/:path*',
destination: 'https://api.myapp.com/:path*'
}]
}
}
// vite.config.ts (Vite)
export default {
server: {
proxy: {
'/api': {
target: 'https://api.myapp.com',
changeOrigin: true
}
}
}
}Verify CORS configuration
Test that CORS headers are correct.
# Test preflight request
curl -X OPTIONS https://api.myapp.com/data \
-H "Origin: https://myapp.com" \
-H "Access-Control-Request-Method: POST" \
-vWhat You'll Achieve
Your API correctly returns CORS headers for your frontend domain. Preflight requests are handled, credentials work across origins, and development uses a proxy instead of wildcard CORS.
Common Mistakes to Avoid
Mistake
Using Access-Control-Allow-Origin: * with credentials
Fix
Wildcard origin does not work with credentials: true. Specify the exact origin or use a dynamic origin check.
Mistake
Setting origin: * in production
Fix
Wildcard CORS allows any website to make requests to your API. Always specify your frontend domain.
Mistake
Adding CORS headers to the frontend
Fix
CORS headers must be set on the server/API, not the frontend. The browser checks the server response for CORS headers.
Frequently Asked Questions
Why does CORS work in Postman but not the browser?
CORS is a browser-only security feature. Postman and curl do not enforce CORS. The error is on the server side: it is not returning the correct Access-Control-Allow-Origin header.
Can I disable CORS?
You should not disable CORS in production. It protects your users from cross-site attacks. Fix the CORS configuration on your server instead.
Why do I get CORS errors on localhost?
Different ports count as different origins (localhost:3000 vs localhost:4000). Use a development proxy or add localhost to your CORS allowed origins for development only.
Ready to Secure Your App?
VAS automatically scans your deployed app for the security issues covered in this guide. Get actionable results in minutes.
Start Security Scan