DevTools Logo

CORS Policy Builder

CORS Policy Builder

Configure cross-origin response headers and server snippets entirely in your browser

CORS configuration

Choose which origins, methods, and headers your server should allow.

Enter one origin per line.

Permit cookies and authorization credentials.

Examples

Single-origin API with auth and preflight caching

Input
Origins: https://app.example.com
Methods: GET, POST, OPTIONS
Request headers: Content-Type, Authorization
Expose headers: (empty)
Credentials: on
Max-Age: 86400
Output
Headers:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Expose-Headers:
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 86400

Even with credentials on, a single explicit origin is safe to echo back. The empty Access-Control-Expose-Headers line is intentional — the browser will not allow any extra response headers to be read by JS.

Multi-tenant API with credentials and three origins

Input
Origins:
  https://a.example.com
  https://b.example.com
  https://c.example.com
Methods: GET, POST, PUT, DELETE, OPTIONS
Request headers: Content-Type, Authorization, X-Request-Id
Expose headers: X-Request-Id, X-RateLimit-Remaining
Credentials: on
Max-Age: 3600
Output
Headers:
Access-Control-Allow-Origin: <request-origin>
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization, X-Request-Id
Access-Control-Expose-Headers: X-Request-Id, X-RateLimit-Remaining
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 3600

Nginx:
add_header Access-Control-Allow-Origin "$http_origin" always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization, X-Request-Id" always;
add_header Access-Control-Expose-Headers "X-Request-Id, X-RateLimit-Remaining" always;
add_header Access-Control-Allow-Credentials "true" always;
add_header Access-Control-Max-Age "3600" always;

Multiple origins trigger the dynamic mode. The header placeholder (<request-origin>) and the Nginx directive ($http_origin) must be validated against a server-side allowlist; do not echo the Origin header verbatim.

Public read-only API with no credentials

Input
Origins: *
Methods: GET, OPTIONS
Request headers: Content-Type
Expose headers: (empty)
Credentials: off
Max-Age: 86400
Output
Headers:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, OPTIONS
Access-Control-Allow-Headers: Content-Type
Access-Control-Expose-Headers:
Access-Control-Allow-Credentials: false
Access-Control-Max-Age: 86400

fetch example:
fetch("https://example.com/api/resource", {
  method: "GET",
  mode: "cors",
  credentials: "omit",
  headers: {
    "Content-Type": "<value>"
  },
})
  .then((response) => response.json())
  .then((data) => console.log(data))

With credentials off, * is a valid Access-Control-Allow-Origin value. The fetch example uses credentials: 'omit' to match the chosen policy.

About this tool

CORS (Cross-Origin Resource Sharing) is the browser security protocol that decides whether code running on one origin may read a response from another. A working policy coordinates the allowed origin, methods, request headers, exposed response headers, credentials, and preflight cache duration; a mismatch in any one of them can block a valid frontend or expose an API more broadly than intended.

CORS Policy Builder turns those choices into three practical outputs: raw Access-Control response headers, Nginx add_header directives, and a JavaScript fetch example. Multiple origins require dynamic server logic because Access-Control-Allow-Origin accepts only one origin or a wildcard. For credentialed requests, the server must validate the incoming Origin against an allowlist before echoing it and cannot return *.

Generation is fully client-side, so origin allowlists and API header names never leave your browser. The output is a configuration aid: apply it to the route that handles both the actual request and its OPTIONS preflight, then verify the response in browser developer tools.

How to use

  1. Set origins and methods

    Enter one allowed origin per line and toggle the HTTP methods your cross-origin clients may use.

  2. Configure header access

    List the request headers accepted by your server and the response headers browser code may read.

  3. Choose credentials and caching

    Enable credentials only for trusted explicit origins, then set how long browsers may cache a successful preflight.

  4. Copy the policy

    Use the Headers, Nginx, or fetch example tab and copy the generated format you need.

Use cases

Configuring a single-origin API

Document the exact Access-Control headers your frontend needs and ship the matching Nginx or Express snippet so the server block and the frontend code stay in sync.

Hardening a multi-tenant API

Multiple origins with credentials need a dynamic origin echo backed by a server-side allowlist. Use the generated $http_origin placeholder together with a custom validator in Nginx or your application layer.

Documenting a public read-only endpoint

A CDN-backed, public, read-only API can ship Access-Control-Allow-Origin: * with no credentials. The Headers tab gives you a copy-paste block for the spec.

Bootstrapping a new frontend client

Use the fetch example to seed a typed API client — the method, mode, credentials, and header names are filled in from the policy so the first request cannot be blocked by a missing preflight response.

Generated CORS formats

FormatUse
HeadersRaw Access-Control response-header lines for documentation or middleware
Nginxadd_header directives for an Nginx server or location block
fetch exampleBrowser request snippet using mode: cors and the chosen credential behavior

Generated locally — no origin or API configuration is uploaded.

Common mistakes

Mistake:Returning Access-Control-Allow-Origin: * together with Access-Control-Allow-Credentials: true.

Fix:The browser blocks the response. With credentials enabled, switch to a single explicit origin or echo the request Origin after validating it against a server-side allowlist.

Mistake:Listing every origin in Access-Control-Allow-Origin as a comma-separated value.

Fix:The header takes a single origin or *. Echo the request Origin header from a server-side allowlist when you need multiple origins with credentials.

Mistake:Forgetting to handle the OPTIONS preflight on the same route.

Fix:Preflight requests are issued against the same URL as the real request. Apply the CORS headers to both the real route and its OPTIONS handler, or use a middleware that short-circuits OPTIONS to 204.

Mistake:Setting Access-Control-Max-Age too short or too long.

Fix:Pick a value that matches how often your policy changes. 600 (10 min) is a safe default while iterating; 86400 (24 h) is fine for a stable policy. Anything past 86400 is clamped by most browsers.

Mistake:Trusting the generated example to be a complete CORS implementation.

Fix:The builder is a documentation aid. You still need to validate the dynamic origin server-side and to apply the policy to every route that the browser may preflight.

Frequently asked questions

References & standards