All templates
Sequence template

CORS preflight request sequence

Browser-to-server handshake for cross-origin requests.

A browser security feature sits between your JavaScript and a cross-origin API: CORS (Cross-Origin Resource Sharing). When your frontend at app.example.com tries to fetch data from api.example.com, the browser doesn't just send the request — it first asks permission with an automatic preflight OPTIONS request. Only if the server says yes does the browser actually send your POST, PUT, or DELETE.

This template shows the handshake: the browser sends an OPTIONS preflight with the origin, requested method, and headers it wants to use. The server responds with an Allow-Origin header (does it trust this origin?) and Allow-Methods (can it use POST?). If both match, the browser unblocks the actual request. If the server says no, the browser blocks the response with a CORS error — and your JavaScript never sees the data.

When to use this template

  • API onboarding docs — show frontend engineers how to set the Content-Type header correctly to avoid unexpected preflights, or document where your CORS policy is enforced.
  • Security audit — trace the preflight handshake so you can verify your Allow-Origin and Allow-Methods headers are restrictive (don't allow * in production).
  • Debugging CORS errors — when a team reports "CORS error in Chrome, works in Postman", diagram the preflight to pinpoint whether the browser is sending it but the server isn't responding, or the server is allowing it but the allow-list is wrong.

How to adapt it

Customize the headers and policies for your setup:

  • Credentials and cookies — add a note that requests with credentials (cookies, auth) require Allow-Credentials: true and must list the origin explicitly (not *).
  • Multiple allowed origins — expand the "Check origin" step to show a lookup table or environment-based list (dev, staging, production allow different origins).
  • Custom headers — add a participant for each custom header your API uses (X-API-Key, X-CSRF-Token) and show them in the Allow-Headers response.

Visual edits regenerate clean code, so you can document your real CORS policy without manual syntax.

Mermaid code

Copy it anywhere Mermaid is supported — GitHub, Notion, or your docs.

sequenceDiagram
    participant Browser
    participant Server
    Browser->>Server: OPTIONS /api/data (preflight)
    Note over Browser,Server: No credentials, CORS headers
    Server->>Server: Check origin, method, headers
    Server->>Browser: 200 OK + CORS headers
    Note over Server,Browser: Allow-Origin, Allow-Methods, Allow-Headers
    alt CORS allowed
        Browser->>Server: POST /api/data (actual request)
        Server->>Browser: 200 OK + data
        Browser->>Browser: JavaScript receives response
    else CORS denied
        Browser->>Browser: Block response, throw CORS error
        Note over Browser: Origin not in Allow-Origin list
    end

Frequently asked questions

What is a CORS preflight request?
It's a safety check the browser runs before sending a request that modifies data (POST, PUT, DELETE) or uses custom headers. The browser first sends an OPTIONS request to see if the server allows cross-origin requests from this origin, method, and headers. The server responds with Allow-Origin and Allow-Methods headers. Only if the preflight passes does the browser send the actual request.
Why does the browser send a preflight at all?
Old browsers didn't understand CORS — if a webpage could make requests anywhere, a malicious site could submit forms to your bank and steal data. The preflight is a speed bump: the attacker's page must get permission from your server before the request lands. Your server's CORS policy controls who gets in.
How do I fix CORS errors in my API?
Add CORS headers to your responses: Access-Control-Allow-Origin (which origins), Access-Control-Allow-Methods (which HTTP verbs), Access-Control-Allow-Headers (which custom headers). Set them on both the preflight OPTIONS response and the actual response. For development, allow localhost:3000; for production, list only your frontend domains. Visual edits let you document your CORS policy without syntax overhead.
When are preflight requests NOT sent?
Simple requests (GET, HEAD, POST with standard content-types) skip the preflight. But custom headers, JSON content-type with POST, credentials cookies, or any PUT/DELETE/PATCH always trigger it. If you're not seeing OPTIONS requests in your network tab, you're probably making simple requests — add a custom header to trigger the preflight so you can test your CORS setup.

Related templates