/public/tools/

CORS preflight analyzer

Describe a cross-origin request and the Access-Control-* headers the server answers with. This tool walks the browser's CORS algorithm the way the browser does: it decides whether a preflight OPTIONS fires, checks whether that preflight passes, then checks whether the actual response is readable, and tells you the exact reason for every block.

presets

analyzing…

    Simple vs preflighted

    The browser sends a preflight OPTIONS before the real request unless the request qualifies as simple. A request is simple only when all three hold: the method is GET, HEAD, or POST; every author-set header is on the CORS-safelist (Accept, Accept-Language, Content-Language, Content-Type, plus Range within limits); and the Content-Type, if present, is one of application/x-www-form-urlencoded, multipart/form-data, or text/plain. The single most common surprise is that Content-Type: application/json is not on that list, so an otherwise simple-looking POST of JSON always triggers a preflight.

    The wildcard and credentials trap

    When the request is made with credentials (cookies, HTTP auth, or client certs, i.e. fetch(url, {credentials: 'include'}) or xhr.withCredentials = true), the wildcards stop working. Access-Control-Allow-Origin: * is rejected outright; the server must echo the exact request origin and add Access-Control-Allow-Credentials: true. The same is true for Access-Control-Allow-Methods: * and Access-Control-Allow-Headers: *: with credentials they match nothing and you must name every method and header explicitly. And even without credentials, Access-Control-Allow-Headers: * never covers Authorization; that one header always has to be listed by name.

    CORS gates reading, not sending

    This is the misconception that burns people. CORS is enforced by the browser, on the response. A blocked cross-origin request usually still reached the server and ran: the browser just refuses to hand the response back to your JavaScript. So CORS is not a defense against a state-changing request, and a blocked request is not proof the server did nothing. Cross-site request forgery is a separate problem with separate defenses (SameSite cookies, CSRF tokens). When you reflect the request origin into Access-Control-Allow-Origin dynamically, add Vary: Origin so a shared cache does not serve one origin's allow header to another.

    What this tool does not model

    It reasons about one request against one set of response headers. It does not fetch anything, follow redirects (which restart CORS with a null origin), evaluate Access-Control-Allow-Private-Network for local-network requests, account for a ReadableStream upload body or upload progress listeners (both of which also force a preflight), or judge whether your Access-Control-Max-Age survives the browser's own cap (Chrome 2 hours, Firefox 24 hours). It assumes the request is genuinely cross-origin; a same-origin request is exempt from CORS entirely.

    Header reference

    headermeaning
    Access-Control-Allow-OriginThe origin allowed to read the response, or * for any. With credentials, must be the exact origin, never *. A single value only, never a list.
    Access-Control-Allow-CredentialsMust be the literal true for a credentialed request to be readable. Absent or anything else means cookies/auth responses are blocked.
    Access-Control-Allow-MethodsPreflight only. The methods allowed for the actual request. * works only without credentials. Safelisted methods (GET/HEAD/POST) are always allowed.
    Access-Control-Allow-HeadersPreflight only. The non-safelisted request headers allowed. * works only without credentials and never covers Authorization.
    Access-Control-Expose-HeadersWhich response headers JavaScript may read beyond the safelisted set. Not a gate; * works only without credentials.
    Access-Control-Max-AgeSeconds the preflight result may be cached. Capped by the browser. Not a gate.
    Vary: OriginNot a CORS header, but required for cache correctness whenever the allow-origin value is computed from the request origin.

    Single static HTML file, no network. Nothing you type leaves the browser. Source: github.com/truffle-dev/tool-cors. MIT.