CORS Preflight Requests Explained with Real OPTIONS Examples

Reviewed September 3, 2026 · Maintained by William

A CORS preflight is the browser asking a server for permission before it sends certain cross-origin requests. It is not an error by itself and it is not a request your JavaScript normally creates manually.

What a preflight looks like

Imagine a page at https://app.example.com wants to send JSON with an authorization header to https://api.example.net/users. The browser may first send:

OPTIONS /users HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization, content-type

The server can approve that origin, method and header set with a response such as:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Authorization, Content-Type
Vary: Origin

Why simple requests sometimes skip preflight

The Fetch standard defines a limited set of “CORS-safelisted” methods and headers. A basic GET or a narrowly shaped form submission may be sent directly. Adding a non-safelisted header, using a method such as PUT, or using many JSON request patterns can trigger the OPTIONS check.

Do not authorize the OPTIONS request and forget the real request

The preflight only tells the browser whether it may continue. Your server must still authenticate and authorize the actual POST/PUT/DELETE request. CORS is a browser access-control protocol, not an authentication system.

Cache carefully

Access-Control-Max-Age can reduce repeated preflights, but browser caps vary. When the allowed origin is selected dynamically, Vary: Origin helps shared caches avoid reusing a response for the wrong origin.

Debugging checklist

  • Open the browser network panel and inspect the OPTIONS request separately from the application request.
  • Confirm the response allows the exact requesting origin when credentials are involved.
  • Confirm the requested method appears in Access-Control-Allow-Methods.
  • Confirm non-safelisted request headers are allowed.
  • Check that redirects, authentication middleware or error pages are not intercepting OPTIONS.

The CORS Header Generator can help draft a narrow policy, while the HTTP Header Parser helps inspect a copied response. Production behavior still belongs to the server/framework configuration.

References

Walk through a preflight from request to response

Assume a browser page at https://app.example wants to send JSON with an authorization header to https://api.example/orders. Because this is not a CORS-safelisted request, the browser can send a preflight before the application request.

OPTIONS /orders HTTP/1.1
Origin: https://app.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization, content-type

A narrowly configured API might answer:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Authorization, Content-Type
Vary: Origin
Access-Control-Max-Age: 600

If the browser accepts that preflight, it can proceed with the POST. The actual POST response must still carry the appropriate Access-Control-Allow-Origin header; passing the preflight does not automatically make the final response readable.

Why “it works in curl” is not a CORS test

cURL is not a web browser and does not enforce the browser same-origin policy. A terminal request can return 200 while browser JavaScript is blocked from reading the same response. When debugging CORS, inspect the browser Network panel and distinguish the OPTIONS request from the application request.

Common preflight failures

SymptomLikely causeCheck
OPTIONS returns 404/405Router/proxy does not handle OPTIONSWeb server, reverse proxy and framework routes
Requested header rejectedHeader missing from allow-listAccess-Control-Allow-Headers
Method rejectedMethod not permittedAccess-Control-Allow-Methods
Correct origin sometimes receives wrong cached responseCache not varying by OriginVary: Origin and CDN behavior
Preflight passes but JS still failsFinal response lacks CORS header or credentials mismatchInspect the POST/GET response too

Do not turn debugging into a permanent wildcard

A frequent emergency fix is to reflect every incoming Origin or allow broad methods/headers. That can hide the immediate error while widening who may call the API from browser contexts. Prefer an explicit allow-list that matches the environments you operate, and keep development origins separate from production policy.

What to capture in a bug report

Record the page origin, target URL, requested method, requested headers, preflight status, preflight response headers and final response headers. That evidence is much more useful than a screenshot of a generic browser CORS error. The HTTP Header Parser can help format captured headers, while the CORS Header Generator is a starting point for configuration—not a replacement for testing the deployed response.

About the review

This guide is maintained by William. Technical claims are checked against primary or authoritative references where applicable. See How We Test CodeNimbleTools for the site-wide review and correction process.