CORS (Cross-Origin Resource Sharing) Guide

Complete CORS reference: preflight requests, Access-Control headers, credentials, wildcard policies, and common pitfalls.

The data

Headers

HeaderDirectionDescriptionExampleNotes
Access-Control-Allow-OriginResponseSpecifies which origins can access the resourceAccess-Control-Allow-Origin: https://example.com OR * (wildcard)Cannot use * with credentials; must echo specific origin for credentialed requests
Access-Control-Allow-MethodsResponse (preflight)Allowed HTTP methods for the resourceAccess-Control-Allow-Methods: GET, POST, DELETEReturned in response to OPTIONS preflight; list only what's actually supported
Access-Control-Allow-HeadersResponse (preflight)Allowed custom headers in requestsAccess-Control-Allow-Headers: Content-Type, Authorization, X-Custom-HeaderMust include all non-simple headers the client needs to send
Access-Control-Expose-HeadersResponseHeaders the browser is allowed to expose to client-side codeAccess-Control-Expose-Headers: X-Total-Count, X-Page-CountBy default, only Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma are exposed
Access-Control-Allow-CredentialsResponseWhether cookies/auth are included in cross-origin requestsAccess-Control-Allow-Credentials: trueRequires Access-Control-Allow-Origin to be a specific origin (not *)
Access-Control-Max-AgeResponse (preflight)How long (seconds) preflight result can be cachedAccess-Control-Max-Age: 86400Reduces preflight overhead; browsers cap this (Chrome: 2h, Firefox: 24h)
OriginRequestClient sends the origin making the requestOrigin: https://example.comSent with all CORS requests; server uses this to decide whether to allow
Access-Control-Request-MethodRequest (preflight)Method that will be used in the actual requestAccess-Control-Request-Method: DELETESent in OPTIONS preflight to ask server if method is allowed
Access-Control-Request-HeadersRequest (preflight)Headers that will be used in the actual requestAccess-Control-Request-Headers: Content-Type, AuthorizationSent in OPTIONS preflight to ask server if headers are allowed

Simple requests

Description
Requests that don't trigger preflight (OPTIONS)
Conditions
  • Method is GET, HEAD, or POST only
  • Headers are only: Accept, Accept-Language, Content-Language, Content-Type (with simple values)
  • Content-Type is application/x-www-form-urlencoded, multipart/form-data, or text/plain
  • No ReadableStream in request body
Notes
POST with application/json triggers preflight! Use application/x-www-form-urlencoded for simple POST.

Common mistakes

MistakeFix
Using * with credentialsEcho the specific Origin header value instead of *
Forgetting to handle OPTIONS methodAdd OPTIONS handler that returns CORS headers for preflight
Not caching preflight responsesAdd Access-Control-Max-Age to preflight responses
Exposing custom headers without Access-Control-Expose-HeadersAdd Access-Control-Expose-Headers for any custom response headers client needs
Returning CORS headers on all responses including errorsEnsure CORS headers are present on 4xx/5xx responses too

Fetch the same bytes

The static files are identical to what the API returns, but with no rate limit and no server round trip. Use the API when you want a query and a content type; use the files when you want to cache one document.

curl "https://yjtoon.com/api/dataset/http-cors-guide?format=toon"
const res = await fetch(
  "https://yjtoon.com/static-data/dataset/http-cors-guide.toon"
);
const toon = await res.text();

Rate limit: 120 requests per minute per IP, no key and no signup. API reference →

Topics

  • http
  • cors
  • cross-origin
  • security
  • preflight
  • access-control
  • same-origin