CORS Deep Dive: Why the Browser Sends Preflight OPTIONS and How to Fix It
Demystifying Cross-Origin Resource Sharing: Same-Origin Policy, simple vs preflighted requests, credentials mode, and secure server headers.
CORS Deep Dive: Why the Browser Sends Preflight OPTIONS and How to Fix It
1. The Core Purpose of the Same-Origin Policy (SOP)
Cross-Origin Resource Sharing (CORS) is a browser-enforced security mechanism, not a server-side firewall. The browser allows JavaScript to read responses only when the target server explicitly grants permission via HTTP headers.
Origin Definition = Scheme (Protocol) + Hostname (Domain) + Port
https://example.com:443 <-- Same Origin
http://example.com:80 <-- Different (Scheme & Port)
https://api.example.com <-- Different (Subdomain)
2. Simple Requests vs Preflight OPTIONS Requests
+--------+ +--------+
| Client | --- 1. OPTIONS /api/data ------> | Server |
| Browser| <--- 2. 204 No Content --------- | |
| | (Access-Control-Allow-*) | |
| | | |
| | --- 3. POST /api/data ---------> | |
| | <--- 4. 200 OK + JSON Body ----- | |
+--------+ +--------+
A request triggers a Preflight OPTIONS request if:
- It uses methods other than
GET,POST, orHEAD. - It includes custom headers like
AuthorizationorContent-Type: application/json. - It enables credentials with custom headers.
3. Critical Headers Breakdown
Access-Control-Allow-Origin: Specifies allowed origin domains.Access-Control-Allow-Methods:GET, POST, PUT, DELETE, OPTIONSAccess-Control-Allow-Headers:Content-Type, Authorization, X-Requested-WithAccess-Control-Allow-Credentials:true(Required when cookies or Authorization headers are sent).
[!WARNING] When
Access-Control-Allow-Credentials: trueis set,Access-Control-Allow-OriginCANNOT be wildcard*. It must be an exact reflecting origin.
4. Express & NestJS Production Implementation
// NestJS Main Configuration
app.enableCors({
origin: (origin, callback) => {
const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',') || [];
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Blocked by CORS policy'));
}
},
credentials: true,
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'X-CSRF-Token'],
maxAge: 86400, // Cache preflight for 24 hours to reduce latency
});
5. Key Takeaways
OPTIONSpreflight requests are an essential security gate, not an error.- Cache preflight responses using
Access-Control-Max-Ageto eliminate redundant round trips. - Configure reverse proxies (Nginx/Cloudflare) or backend CORS middleware to reflect explicit whitelist origins.
Recommended Posts
Related Projects
Real estate operating system featuring multi-role workflows, WhatsApp alerts, and geospatial mapping in Cairo & Giza.
An operational travel agency management engine engineered with NestJS and Prisma for booking workflows, multi-currency customer invoicing, dynamic itinerary building, and passenger manifests.
A membership-based private travel club combining curated luxury hotel discovery, protected member pricing, structured booking requests, and a dedicated concierge-led travel operation.