CORS tester
Send the preflight a browser would send from an origin you choose, then check Access-Control-Allow-Origin, methods, headers, credentials, Vary and Max-Age the way the browser does, with the reason a request is blocked and a curl command to repeat it.
What it checks
- Whether the browser needs a preflight at all: it does for methods other than GET, HEAD and POST, and for requests that set headers such as
Authorizationor a JSONContent-Type. - The preflight (an
OPTIONSrequest): a 2xx status with no redirect,Access-Control-Allow-Originmatching your origin, the method inAccess-Control-Allow-Methods, every header inAccess-Control-Allow-Headers, and how longAccess-Control-Max-Agelets the browser cache it. - The response itself: exactly one allowed origin (or
*),Access-Control-Allow-Credentials: truewhen cookies are sent,Vary: Originwhen the origin is echoed, and which response headers scripts can read. - The rules that trip people up:
*never works with credentials, the wildcard inAccess-Control-Allow-Headersnever coversAuthorization, origins and method names are compared exactly, and allowing thenullorigin lets any site in.
Only the preflight and a GET are ever sent. A POST, PUT, PATCH or DELETE could change data, so for those the response checks use a GET to the same URL with the same Origin.
Reading a CORS error
The browser makes the request either way; CORS only decides whether the page's script may read the response. That is why the console shows "blocked by CORS policy" even though the server logged the request, and why a tool like curl, which has no same-origin policy, works fine.
Fix CORS on the server that owns the API, not in the page: answer OPTIONS before authentication and routing, echo back an allowed origin from a list rather than any origin, and add Vary: Origin so caches keep each origin's answer apart.
Questions
- Why does my request work in curl but not in the browser?
- curl doesn't enforce the same-origin policy, so it never sends a preflight or checks the CORS headers. The browser does both, and blocks the page from reading the response when the headers don't allow its origin.
- Can I use Access-Control-Allow-Origin: * with cookies?
- No. With credentials the server must name the exact origin and send Access-Control-Allow-Credentials: true. To allow several sites, check the request's Origin against your list and echo back the one that matches.
- Why does the preflight fail with 401 or 405?
- Preflights carry no cookies or Authorization header, and many frameworks don't route OPTIONS. The CORS handling has to answer OPTIONS requests itself, before authentication and before the router returns 404 or 405.
- Is reflecting the Origin header safe?
- Only if you check it against a list first. A server that echoes any origin with credentials allowed lets every website read your signed-in users' data.
Related tools
- HTTP headersRedirect chain, response headers and a security grade.
- CSP evaluatorHow well does a Content-Security-Policy stop XSS?
- Cookie inspectorAre a site's cookies Secure, HttpOnly and SameSite, and will browsers accept them?
- Website healthEvery address, every entry point and upcoming expiries on one scorecard.