Why Access-Control-Allow-Origin: * Fails with Credentials

Reviewed September 3, 2026 · Maintained by William

The combination Access-Control-Allow-Origin: * and credentialed browser requests is intentionally restricted. A wildcard says “any origin,” while credentials can include cookies, client certificates or HTTP authentication tied to a user. Browsers require a more specific trust decision.

The failing pattern

Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

If client JavaScript sends a credentialed request, the browser will not expose that response to the page under the wildcard policy.

The safer pattern

Maintain an allowlist and return the exact allowed origin:

Origin: https://app.example.com

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true
Vary: Origin

If the request comes from an untrusted origin, do not emit a permissive allow-origin response.

Why blindly reflecting Origin is also dangerous

A common shortcut is to read the incoming Origin header and echo it back. Without validation, that turns any requesting website into an allowed origin and defeats the purpose of the restriction. Reflection is only safe when it follows a real allowlist check.

Credentials do not mean “Authorization header only”

Fetch credentials mode affects browser-managed credentials such as cookies. Custom Authorization headers have their own preflight implications. Treat both authentication and CORS as separate controls: first decide which origin may call the API from a browser, then decide which user/service is authorized.

Practical server rule

  • Keep a normalized set of approved origins.
  • Compare the request Origin against that set.
  • Return the exact matched origin and Vary: Origin.
  • Return Access-Control-Allow-Credentials: true only when the application actually needs credentialed cross-origin requests.
  • Reject or omit CORS approval for every other origin.

The CORS Header Generator deliberately warns about wildcard + credentials because a generator should not encourage a combination browsers reject.

References

The credentialed-request rule in practical terms

When browser JavaScript sends credentials—such as cookies, HTTP authentication or a credentialed fetch mode—the server cannot combine that behavior with a wildcard Access-Control-Allow-Origin: * response and expect the browser to expose the result. The server needs to return a specific allowed origin and, when appropriate, Access-Control-Allow-Credentials: true.

fetch('https://api.example/profile', {
  credentials: 'include'
});

For a request originating at https://app.example, an allow-listed response can look like:

Access-Control-Allow-Origin: https://app.example
Access-Control-Allow-Credentials: true
Vary: Origin

Why blind origin reflection is not an allow-list

A dangerous pattern reads the request Origin header and writes it straight back to Access-Control-Allow-Origin. That produces a specific-looking value, but it effectively approves every requesting website. Instead, normalize and compare the incoming origin against a configured set of exact origins before returning it.

allowed = {
  "https://app.example",
  "https://admin.example"
}

if request.origin in allowed:
    response.allow_origin = request.origin

The actual implementation depends on your framework, but the policy should be explicit. Be cautious with substring checks such as “ends with example.com”; hostile names like example.com.attacker.test can defeat sloppy matching.

Cookies add another policy layer

Even correct CORS headers do not override cookie rules. Cross-site cookies can be affected by SameSite, Secure, domain/path attributes and browser privacy behavior. If a credentialed request reaches the API without the expected cookie, inspect cookie storage and request headers before changing CORS.

Debugging sequence

  1. Confirm the exact origin shown by the browser, including scheme and port.
  2. Check whether the request is credentialed.
  3. Inspect the preflight response if one exists.
  4. Inspect the final response, not just OPTIONS.
  5. Verify that the returned allow-origin value is one explicitly trusted by the API.
  6. For dynamic origins, verify Vary: Origin so shared caches do not serve one origin’s CORS response to another.
  7. Only then investigate cookie SameSite or authentication/session behavior.

When a wildcard is appropriate

A wildcard can be appropriate for genuinely public, non-credentialed resources where any website may read the response. That is a product/security choice, not a shortcut to make errors disappear. If a public endpoint later starts returning user-specific or session-bound data, revisit the policy rather than leaving the old wildcard in place.

About the review

This guide is maintained by William. Technical claims are checked against primary or authoritative references where applicable. See How We Test CodeNimbleTools for the site-wide review and correction process.