ć‚†ć‚‹ćƒ†ćƒƒć‚ÆćƒŽćƒ¼ćƒˆ

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.