Access-Control-Allow-Credentials: true, and why * fails (tested in Chrome)

Sending cookies cross-origin needs two response headers: the exact origin (not *) and Access-Control-Allow-Credentials: true. We tested every combination in Chrome.

1. The matrix

Response headersfetch credentialsPage got the response?Cookie reached the server?
ACAO *omit (no cookies)YesNo
ACAO *includeBlockedYes
ACAO * + ACAC trueincludeBlockedYes
ACAO http://localhost:8997includeBlockedYes
ACAO http://localhost:8997 + ACAC trueincludeYesYes

The two errors Chrome printed:

The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.

The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'.

2. The fix

Access-Control-Allow-Origin: https://app.example.com   # the caller's exact origin, from an allow-list
Access-Control-Allow-Credentials: true
Vary: Origin

Echo the request's Origin only if it is on your list: our multiple-origins guide has a tested nginx map. Echoing any origin together with credentials lets every website read your users' data. Add Vary: Origin so caches don't hand one origin's header to another (measured here). On the client, fetch(url, {credentials: "include"}) or xhr.withCredentials = true (axios: withCredentials: true).

3. CORS doesn't stop the request

In every blocked row the cookie still reached the server; only the page was prevented from reading the answer. So a cross-site POST that changes data still runs. Protect such endpoints with SameSite cookies and CSRF tokens; CORS isn't a CSRF defence. (The cookie here was SameSite=None; a Lax cookie wouldn't be sent on a cross-site fetch at all.)

Frequently asked questions

Can I use Access-Control-Allow-Credentials true with Access-Control-Allow-Origin *?

No. Chrome blocked it with 'must not be the wildcard * when the request's credentials mode is include'. Return the caller's exact origin instead.

What does Access-Control-Allow-Credentials true mean?

That the page may read the response of a request sent with cookies or HTTP auth. Without it, our credentialed fetch was blocked even with the exact origin.

Are cookies sent if the CORS check fails?

Yes. In our test the cookie reached the server in every blocked case; the browser only hid the response from the page.

Do I need Access-Control-Allow-Credentials for requests without cookies?

No. With credentials 'omit' (or the fetch default for cross-origin), ACAO * worked on its own.

Written with AI assistance. Measured on 2026-10-01 in Chromium 153 (full build): a page on localhost:8997 called fetch() on 127.0.0.1:8998, which had set a cookie (SameSite=None; Secure), with each combination of response headers and credentials mode. The server logged whether the cookie arrived; the console errors are quoted as Chrome printed them. The XHR/axios flags and the fetch default are from their documentation, not this test. PlainHeaders is our extension; the other methods are free.