CORS preflight and OPTIONS
Ever saw an OPTIONS request before your POST? That is a CORS preflight. Here is when it happens and how to respond.
When does it fire?
Browsers send OPTIONS before non-simple requests per the Fetch Standard.
Typical triggers
- Methods other than GET/HEAD/POST (PUT/PATCH/DELETE, etc.).
- POST with a non-simple Content-Type such as application/json.
- Custom headers (X-*, Authorization, etc.).
Headers the browser sends
Preflight does not touch the resource; it just asks permission.
Key headers
| Header | Meaning |
|---|---|
| Origin | Scheme + host + port of the requester. |
| Access-Control-Request-Method | Method intended for the actual request. |
| Access-Control-Request-Headers | Request headers intended for the actual request (lowercase, comma-separated). |
How to respond
Do not return the real resource. Only declare what is allowed.
Allow headers
| Header | Role |
|---|---|
| Access-Control-Allow-Origin | Allowed origin. Wildcard cannot be used with credentials. |
| Access-Control-Allow-Methods | Allowed methods (GET, POST, PUT, etc.). |
| Access-Control-Allow-Headers | Allowed request headers. |
| Access-Control-Max-Age | Seconds to cache the preflight result. Long values delay config changes. |
| Access-Control-Allow-Credentials | true when cookies/Authorization are allowed. Not with *. |
Status codes
- 204 No Content is simplest; 200 is also fine, but the body is unused.
- If not allowed, return 403 or similar without Allow headers.
Common pitfalls
Mismatched header names and middleware order cause most failures.
Checklist
- Access-Control-Allow-Headers must exactly match what the client sends (lowercased names).
- If allowing credentials, set Allow-Origin to the specific origin, not *.
- Ensure OPTIONS passes auth/routing middleware instead of being blocked early.
- Keep Access-Control-Max-Age reasonable; long values slow down config changes.
Takeaway
Preflight is a lightweight permission check. Return the Allow headers tailored to the Origin, and the actual request will flow smoothly.