Skip to content
apikey.tools
ENVEnvironment

CORS Header & API Access Configuration Generator

Generate correct CORS headers for nginx, Express or Next.js — and see the combination that cannot work.

ENVRuns in this tabInput not transmitted

Input

sec

Output

computing

CORS is frequently misunderstood as a security control. It is not one. It is a browser policy that decides whether *browser JavaScript* may read a cross-origin response. It does nothing to stop curl, a server, a mobile app or an attacker with a script.

Your API keys and authorisation checks are what protect your API. CORS only decides which web pages may call it from a user's browser.

The combination that cannot work

Access-Control-Allow-Origin: * together with Access-Control-Allow-Credentials: true is rejected by every browser. The specification forbids it, because it would let any site on the internet make authenticated requests with the user's cookies.

The fix is to echo a specific, validated origin. The dangerous non-fix is to reflect whatever origin the request sent:

javascript
// Vulnerable — reflects any origin, defeating CORS entirely
res.setHeader("Access-Control-Allow-Origin", req.headers.origin);

// Correct — check against an allowlist first
const allowed = new Set(["https://app.example.com"]);
const origin = req.headers.origin;
if (origin && allowed.has(origin)) {
  res.setHeader("Access-Control-Allow-Origin", origin);
  res.setHeader("Vary", "Origin");
}

Always send Vary: Origin

When the allowed origin depends on the request, the response varies by the Origin header. Without Vary: Origin, a CDN or shared cache stores the response for one origin and serves it to another — which either breaks legitimate requests or leaks a response across origins.

This is a real and commonly missed bug. Every generated configuration here includes it.

Preflight

For anything other than a simple request — a custom header like Authorization, a Content-Type of application/json, or a method other than GET, POST or HEAD — the browser sends an OPTIONS preflight first.

The preflight response must include the allowed methods and headers, and must not require authentication. A preflight blocked by your auth middleware produces a CORS error that looks like a CORS misconfiguration but is actually an auth ordering problem.

Access-Control-Max-Age caches the preflight result. 86400 seconds removes an entire round trip from most requests. Browsers cap it — Chrome at 2 hours, Firefox at 24 — so a larger value is silently reduced rather than honoured.

Wildcard is fine for genuinely public APIs

If your API requires no credentials and serves public data, * is correct and simpler. The moment authentication is involved, list origins explicitly.

Frequently asked questions

Why does my request work in Postman but fail in the browser?

Postman is not a browser and does not enforce CORS. The failure is entirely browser-side policy. The request is reaching your server; the browser is refusing to let JavaScript read the response.

Does CORS protect my API?

No. It protects your users' browsers from other websites reading responses on their behalf. An attacker calls your API directly, where CORS never applies. Authentication and authorisation are what protect the API.

Why does the preflight fail with a 401?

Your authentication middleware is running before the CORS handler and rejecting the OPTIONS request, which carries no credentials by design. Handle OPTIONS before authentication.

Can I allow all origins but still use cookies?

No. That combination is forbidden by the specification. Validate the origin against an allowlist and echo it back, with Vary: Origin.

More environment tools

Emit secrets into the config format you deploy