CORS (Cross-Origin Resource Sharing)
A browser security mechanism that restricts web pages from making requests to a different origin than the one that served the page. Servers opt into cross-origin access by returning specific HTTP headers that tell the browser which origins, methods, and headers are permitted.
CORS (Cross-Origin Resource Sharing) is a browser security feature that prevents web pages from making requests to a different origin (domain, protocol, or port) than the one that loaded the page. This is called the Same-Origin Policy. CORS provides a controlled way for servers to relax this restriction by declaring which external origins are allowed.
What Is an Origin?
An origin is the combination of protocol + hostname + port:
https://app.example.com:443 ← origin
│ │ │
protocol hostname port
These are all different origins from https://app.example.com:
http://app.example.com— different protocolhttps://api.example.com— different subdomainhttps://app.example.com:8080— different port
Simple vs Preflight Requests
Simple requests (GET/POST with basic headers) are sent directly — the browser checks CORS on the response.
Preflighted requests (PUT/DELETE, or requests with custom headers like Authorization) trigger an automatic OPTIONS request first. The server must respond with CORS headers before the actual request is sent.
OPTIONS /api/users HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Authorization, Content-Type
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 86400
CORS Response Headers
Access-Control-Allow-Origin: https://app.example.com
# Or wildcard (cannot be used with credentials):
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type, X-Api-Key
Access-Control-Allow-Credentials: true # send cookies cross-origin
Access-Control-Max-Age: 86400 # cache preflight for 24 hours
Access-Control-Expose-Headers: X-Total-Count # expose to JS
Express.js CORS Setup
import cors from "cors";
// Allow specific origin
app.use(cors({
origin: "https://app.example.com",
methods: ["GET", "POST", "PUT", "DELETE"],
allowedHeaders: ["Authorization", "Content-Type"],
credentials: true, // required for cookies
maxAge: 86400,
}));
// Allow multiple origins
const allowedOrigins = ["https://app.example.com", "https://admin.example.com"];
app.use(cors({
origin: (origin, callback) => {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error("Not allowed by CORS"));
}
},
}));
Common CORS Errors
| Error | Cause | Fix |
|---|---|---|
| "No 'Access-Control-Allow-Origin' header" | Server not sending CORS headers | Add CORS middleware |
| "CORS policy: credential flag is 'true'" | * used with credentials | Use specific origin, not * |
| "Method not allowed by CORS" | Method not in Allow-Methods | Add method to allowedMethods |
| Preflight 404 | No OPTIONS handler | Handle OPTIONS or use cors() middleware |
Related Terms
- URL Encoding — encoding used in cross-origin request URLs
- JWT — tokens commonly sent in cross-origin
Authorizationheaders
Tools
- CORS Header Tester — inspect CORS headers on any URL