CORS & API Headers Cheat Sheet
Quick reference for CORS and API headers: preflight requests, response headers, Authorization, caching, and common configurations.
Web & Network
cors
headers
http
Cross-Origin Resource Sharing (CORS) lets a browser call your API from another origin. The browser enforces it: the server must answer preflight and simple requests with the right Access-Control-* headers.
Simple vs Preflight
Table
| Request type | Headers that trigger preflight | Server response |
|---|---|---|
| Simple | GET/POST/HEAD, no custom headers, Content-Type in text/plain, multipart/form-data, application/x-www-form-urlencoded | No preflight — response headers only |
| Preflight | Custom headers, Content-Type: application/json, PUT/DELETE/PATCH, credentials | Browser sends OPTIONS first; server must answer before the real request |
http
OPTIONS /api/items HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization, content-type
Response Headers Reference
Table
| Header | Meaning | Typical value |
|---|---|---|
Access-Control-Allow-Origin | Which origin(s) may read the response | https://app.example.com (or *) |
Access-Control-Allow-Methods | Allowed methods for the preflight | GET, POST, PUT, DELETE, OPTIONS |
Access-Control-Allow-Headers | Allowed request headers | Authorization, Content-Type |
Access-Control-Expose-Headers | Response headers readable by JS | X-Total-Count, Link |
Access-Control-Allow-Credentials | Allow cookies/auth with the request | true |
Access-Control-Max-Age | Cache the preflight answer (seconds) | 86400 |
Server Examples
bash
# Simple: allow one origin
curl -sI -H "Origin: https://app.example.com" https://api.example.com/health
# Expect: access-control-allow-origin: https://app.example.com
javascript
// Express
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "https://app.example.com");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
res.setHeader("Access-Control-Allow-Credentials", "true");
res.setHeader("Access-Control-Max-Age", "86400");
if (req.method === "OPTIONS") return res.sendStatus(204);
next();
});
nginx
# NGINX
add_header Access-Control-Allow-Origin "https://app.example.com" always;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
if ($request_method = OPTIONS) { return 204; }
Caching Headers
Table
| Header | Purpose | Example |
|---|---|---|
Cache-Control | Cache directives | public, max-age=3600 |
ETag | Validator for conditional requests | "33a64df5" |
Last-Modified | Date-based validator | Wed, 11 Aug 2026 09:00:00 GMT |
If-None-Match / If-Modified-Since | Request-side validators | match the ETag |
Common Pitfalls
[!WARNING]
Access-Control-Allow-Origin: *combined withAccess-Control-Allow-Credentials: trueis invalid — the browser will reject the response. With credentials you must echo the exact origin and setVary: Origin.
[!TIP] Always send
Vary: Originwhen the allowed origin is dynamic; otherwise shared caches (CDNs) may serve one origin's CORS headers to everyone.