CORS controls how browsers allow cross-origin requests between different domains.
How CORS Works#
Browser (https://app.com) Server (https://api.com)
│ │
│──── Preflight (OPTIONS) ──────────▶│
│ Origin: https://app.com │
│ Access-Control-Request-Method │
│ │
│◀─── CORS Headers ─────────────────│
│ Access-Control-Allow-Origin │
│ Access-Control-Allow-Methods │
│ │
│──── Actual Request (POST) ────────▶│
│ Origin: https://app.com │
│ │
│◀─── Response + CORS Headers ──────│
Simple vs Preflight Requests#
1// Simple request (no preflight)
2// GET, HEAD, POST with simple headers
3fetch('https://api.com/data');
4
5// Preflight required
6// Custom headers, PUT/DELETE, JSON content-type
7fetch('https://api.com/data', {
8 method: 'POST',
9 headers: {
10 'Content-Type': 'application/json',
11 'Authorization': 'Bearer token',
12 },
13 body: JSON.stringify({ data: 'value' }),
14});Express CORS Configuration#
1import cors from 'cors';
2
3// Basic - allow all origins (development only!)
4app.use(cors());
5
6// Production configuration
7app.use(cors({
8 origin: ['https://app.com', 'https://admin.app.com'],
9 methods: ['GET', 'POST', 'PUT', 'DELETE'],
10 allowedHeaders: ['Content-Type', 'Authorization'],
11 credentials: true,
12 maxAge: 86400, // Cache preflight for 24 hours
13}));
14
15// Dynamic origin validation
16app.use(cors({
17 origin: (origin, callback) => {
18 const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',') || [];
19
20 // Allow requests with no origin (mobile apps, curl)
21 if (!origin) return callback(null, true);
22
23 if (allowedOrigins.includes(origin)) {
24 callback(null, true);
25 } else {
26 callback(new Error('Not allowed by CORS'));
27 }
28 },
29 credentials: true,
30}));Manual CORS Headers#
1app.use((req, res, next) => {
2 const origin = req.headers.origin;
3 const allowedOrigins = ['https://app.com'];
4
5 if (allowedOrigins.includes(origin)) {
6 res.setHeader('Access-Control-Allow-Origin', origin);
7 }
8
9 res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
10 res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
11 res.setHeader('Access-Control-Allow-Credentials', 'true');
12 res.setHeader('Access-Control-Max-Age', '86400');
13
14 // Handle preflight
15 if (req.method === 'OPTIONS') {
16 return res.status(204).end();
17 }
18
19 next();
20});Common CORS Headers#
1// Response headers (server sets these)
2'Access-Control-Allow-Origin': 'https://app.com' // or '*'
3'Access-Control-Allow-Methods': 'GET, POST, PUT'
4'Access-Control-Allow-Headers': 'Content-Type'
5'Access-Control-Allow-Credentials': 'true'
6'Access-Control-Max-Age': '86400'
7'Access-Control-Expose-Headers': 'X-Custom-Header'
8
9// Request headers (browser sets these)
10'Origin': 'https://app.com'
11'Access-Control-Request-Method': 'POST'
12'Access-Control-Request-Headers': 'Content-Type'Credentials and Cookies#
1// Server must allow credentials
2app.use(cors({
3 origin: 'https://app.com', // Can't use '*' with credentials
4 credentials: true,
5}));
6
7// Client must include credentials
8fetch('https://api.com/data', {
9 credentials: 'include',
10});Common Issues#
1// ❌ Wildcard with credentials
2res.setHeader('Access-Control-Allow-Origin', '*');
3res.setHeader('Access-Control-Allow-Credentials', 'true');
4// Error: Cannot use wildcard with credentials
5
6// ✅ Specific origin with credentials
7res.setHeader('Access-Control-Allow-Origin', 'https://app.com');
8res.setHeader('Access-Control-Allow-Credentials', 'true');
9
10// ❌ Missing Content-Type in allowed headers
11fetch('/api', {
12 headers: { 'Content-Type': 'application/json' },
13});
14// Preflight fails if Content-Type not in Access-Control-Allow-Headers
15
16// ✅ Include all required headers
17res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');Debugging CORS#
1// Browser console shows CORS errors
2// Check Network tab for preflight (OPTIONS) requests
3
4// Server-side logging
5app.use((req, res, next) => {
6 console.log('Origin:', req.headers.origin);
7 console.log('Method:', req.method);
8 console.log('Headers:', req.headers);
9 next();
10});CORS protects users by restricting cross-origin requests. Configure it properly for security and functionality.