Free tool · no signup

CORS tester and config generator

Describe the request your page makes, paste the responses, and see whether the browser will allow it. If not, you get the exact reason and the header to change.

By the Bug Circuit security team · Last updated

The request your page makes

Verdict
The browser blocks it
  • The browser sends a preflight OPTIONS request first, because of the method PUT and the header authorization and the content type application/json.
Preflight

The request includes credentials, but the response does not send Access-Control-Allow-Credentials: true.

Fix: Send Access-Control-Allow-Credentials: true, or stop sending credentials from the page.

Preflight

PUT is not listed in Access-Control-Allow-Methods (GET, POST).

Fix: Add PUT to Access-Control-Allow-Methods.

Preflight

The request header authorization is not allowed by Access-Control-Allow-Headers (content-type).

Fix: Add authorization to Access-Control-Allow-Headers. A * does not cover Authorization, it must be named. A * does not work when credentials are sent.

Response

The request includes credentials, but the response does not send Access-Control-Allow-Credentials: true.

Fix: Send Access-Control-Allow-Credentials: true, or stop sending credentials from the page.

  • The preflight has no Access-Control-Max-Age, so the browser repeats it for every request (up to the browser default of 5 seconds, or 2 hours in Chrome). Add a value such as 600 to cut the extra requests.
  • The response names one origin but has no Vary: Origin. A cache can then serve the wrong origin's answer to another site. Add Vary: Origin.
Why does the browser block my request? Because the other server did not say that your page is allowed to read the answer. The server must send an Access-Control-Allow-Origin header that matches your origin, and for some requests answer a preflight first. This tool checks each rule and names the one that fails.

How it works

What CORS is, and is not

Browsers stop a page on one origin (scheme, host and port) from reading responses from another unless the other server agrees. That agreement is CORS, and it is enforced by the browser only. The request still reaches the server, which is why CORS does not protect an API from being called by anyone, and why a server that allows every origin is not a security hole unless the response is private to the user.

A simple request, such as a GET or a form POST with no special headers, is sent directly, and the browser then checks the Access-Control-Allow-Origin header in the response. Any other request first triggers a preflight: an OPTIONS request that asks the server whether the real one is allowed.

When a preflight happens, and what it must say

A preflight is sent when the method is not GET, HEAD or POST, when the request carries a header other than the few safe ones (Authorization and X-Api-Key are the usual triggers), or when the body type is not form data or plain text, which includes JSON. The server must answer with a 2xx status and the right headers: Access-Control-Allow-Origin with your origin, Access-Control-Allow-Methods listing the method, and Access-Control-Allow-Headers listing each custom header. When credentials are sent, it must also send Access-Control-Allow-Credentials: true.

Two rules catch most people. A wildcard * does not work when cookies or credentials are sent, so the server must name the exact origin. And a * in Access-Control-Allow-Headers does not cover the Authorization header, which has to be listed by name.

Fixing it safely

Compare the incoming Origin header against a fixed list on the server, and send back only the one that matches, with Vary: Origin so caches do not mix answers up. Do not copy the Origin header back without checking it, because that allows every site while looking strict. The generator tab writes an allow-list for Nginx, Apache and Express. For local development, a proxy in your dev server avoids CORS altogether.

Worked examples

A JSON PUT with a login token

Page https://app.example.com calls PUT https://api.example.com/items with Authorization and a JSON body.

Preflight needed: the method PUT and the header authorization.
The preflight must allow PUT, allow the authorization header, and send Allow-Origin: https://app.example.com.

Either condition alone triggers a preflight. Together they make the server list both the method and the header.

The wildcard with cookies

credentials: include, and the server sends Access-Control-Allow-Origin: *.

Blocked: the request includes credentials, and the server answers *.
Fix: send the exact origin, and add Vary: Origin.

Browsers refuse the combination, whatever the other headers say.

Allowed with a preflight cache

A correct preflight and response, with Access-Control-Max-Age: 600.

The browser allows it.

Max-Age lets the browser skip the preflight for ten minutes, which cuts the extra requests.

Frequently asked questions

What does the CORS error mean?
The browser blocked your JavaScript from reading the response because the server did not allow your origin. The server must send an Access-Control-Allow-Origin header that matches the page that made the request.
Is it safe to set Access-Control-Allow-Origin to *?
For public data that anyone may read, yes. Never for responses that depend on a login, because a wildcard cannot be combined with credentials and tempts people to reflect the Origin header, which is unsafe.
Why does my request send an OPTIONS call first?
That is the preflight. It happens when the method, a header or the body type is not one of the browser's safe defaults, for example a JSON body or an Authorization header.
Does CORS protect my API?
No. It only controls which web pages may read the answers in a browser. Attackers and scripts outside a browser ignore it, so the API still needs authentication and authorisation.
Why is Authorization not covered by a wildcard?
The standard excludes it on purpose, so a server that allows all headers does not accidentally allow credentials-bearing ones. List authorization by name.
What is Vary: Origin for?
When the response depends on the request Origin, caches must keep a separate copy per origin. Without Vary: Origin a cache can serve one site's allow header to another site.
How do I avoid CORS during development?
Proxy API calls through your dev server so the browser sees the same origin, or run the front end and the API behind one domain with a path prefix.

Keep reading

See what attackers see, for free

Run the free passive check on your website. No login, no impact on your site, results in seconds.

Ready for the full manual audit? See pricing

CORS Tester and Config Generator · Bug Circuit