intermediate

CORS and preflight requests

Diagnose origin checks, simple versus preflighted requests, allowed headers/methods, credentials, caching, and server-side CORS policy.

CORS is enforced by browsers, not by curl or server-to-server calls. Simple cross-origin GET/POST may proceed without preflight; requests with custom headers, non-simple content types, or methods like PUT/DELETE trigger an OPTIONS preflight.

					// Express example — reflect allowed origin, never * with credentials
app.use((req, res, next) => {
  const origin = req.headers.origin;
  if (allowedOrigins.has(origin)) {
    res.setHeader('Access-Control-Allow-Origin', origin);
    res.setHeader('Access-Control-Allow-Credentials', 'true');
  }
  if (req.method === 'OPTIONS') {
    res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
    return res.status(204).end();
  }
  next();
});
				

The server must answer preflight before the browser sends the real request. `Access-Control-Expose-Headers` lists response headers JavaScript may read.

On interviews: debug "CORS error" as often a failed preflight or missing exposed header; explain why CORS is not a substitute for authentication.

Common pitfalls: reflecting any Origin in production; wildcard with credentials; caching preflight too aggressively after policy changes.

The trade-off is balancing simplicity, performance, safety, and operability — name which axis you optimized and what cost you accepted.

Checklist:

  • Know simple vs preflighted request rules.
  • Reflect specific origins when using cookies.
  • Handle OPTIONS on API routes explicitly.
  • Test from a real browser origin.