A CORS preflight request fails
Compare the browser's requested CORS permission with the exact preflight response.
- cors
- preflight
- diagnostics
Diagnostic overview
Symptoms
- The browser sends OPTIONS but never sends the intended cross-origin request.
- The preflight response is successful HTTP but the browser still rejects it.
Likely layers
client, proxy, cdn, origin, protocol
Common causes
- OPTIONS is blocked, redirected, or requires credentials before CORS handling.
- The allowed origin, method, or field list does not cover the requested values.
- A proxy handles OPTIONS differently from the application route.
Diagnostic steps
Capture Origin, Access-Control-Request-Method, and Access-Control-Request-Headers.
Look for: These fields are the permission the browser is asking for.
Inspect the preflight status and all Access-Control-Allow response fields.
Look for: An exact mismatch identifies the denied dimension.
Trace OPTIONS through proxy and application routing without credentials.
Look for: A redirect, challenge, or missing route identifies the failing layer.
Targeted fixes
- Handle OPTIONS on the same public route before ordinary authentication when safe and intended.
- Allow only the required origins, methods, and request fields with compatible values.
- Add preflight caching only after correctness and use a bounded max age.
Read the permission request
The browser-generated preflight describes the intended request.
OPTIONS /records HTTP/1.1
Origin: https://app.example.invalid
Access-Control-Request-Method: PATCH
Access-Control-Request-Headers: content-type, if-match
Expected result: the server must decide whether that origin may use PATCH with both named fields. A generic 204 without matching allow fields is not sufficient.
Trace OPTIONS independently
Route, firewall, CDN, and authentication behavior can differ for OPTIONS. Capture the first response without following redirects. The preflight normally does not include the credentials of the later request.
Match only what is needed
Return the allowed origin, method, and field names required by the request. Avoid expanding the policy to every origin or method as a diagnostic shortcut.
