Developers configuring CORS often set Access-Control-Allow-Origin: * assuming it will grant access to all clients. However, as soon as authentication cookies or credentials are attached, the browser reports a failure: 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'.
What browser credentials mean in CORS
In the context of the Fetch API and XMLHttpRequest, “credentials” refers to ambient or explicit user authentication tokens automatically managed by the browser:
- HTTP cookies (session cookies, tracking cookies)
- HTTP authentication headers (such as
Authorization: Basic ...) - TLS client certificates
When client JavaScript executes fetch('https://api.example.test/user', { credentials: 'include' }), it instructs the browser to attach stored cookies for api.example.test to the cross-origin request.
Why wildcard origin and credentials conflict
Allowing a wildcard origin * with credentials would create a catastrophic security vulnerability:
If any website on the internet could make credentialed requests to api.example.test and read the responses via Access-Control-Allow-Origin: *, an attacker’s website could read the private personal data of any logged-in user who visits their site.
To protect user privacy, the CORS specification requires that any response exposing credentialed data must explicitly name the authorized origin.
Access-Control-Allow-Credentials
The Access-Control-Allow-Credentials header informs the browser whether the server permits sharing the response when credentials are sent.
Its only valid value is true (case-sensitive). If omitted, or set to false, the browser will not expose the response to frontend JavaScript, even if the origin matches.
Specific allowed origins and server ownership
To support credentialed cross-origin requests securely:
- The server reads the incoming
Originrequest header (e.g.,Origin: https://app.example.test). - The server verifies whether
https://app.example.testexists in an internal allowlist of trusted origins. - If valid, the server echoes that specific origin back in the
Access-Control-Allow-Originheader:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://app.example.test
Access-Control-Allow-Credentials: true
Cookies, Authorization, and careful distinctions
Note the following distinctions:
- Session cookies: Always require
credentials: 'include'and explicit origins. - Bearer tokens: When tokens are stored in JavaScript memory and passed via
Authorization: Bearer <token>, they do not technically requirecredentials: 'include', but they do requireAccess-Control-Allow-Headers: Authorizationand preflight approval.
What to inspect in DevTools
- Open DevTools > Network tab.
- Select the failed request.
- Look at Response Headers:
- Check if
Access-Control-Allow-Originis set to*. - Check if
Access-Control-Allow-Credentialsis missing or not set totrue.
- Check if
- Check Request Headers for
CookieorAuthorization.
What not to do
- Do NOT blindly reflect any Origin header: Echoing back arbitrary origins without validation effectively recreates the insecure wildcard behavior.
- Do NOT use public CORS proxies: Passing credentials through third-party proxies exposes sensitive cookies and tokens.
- Do NOT disable browser security: Bypassing security checks in local development masks production configuration failures.
Common causes
Server Uses Wildcard Origin on Credentialed Request
The backend server responds with Access-Control-Allow-Origin: * to a request sent with credentials: 'include', which the browser security model rejects.
Missing Access-Control-Allow-Credentials Header
The server returns an explicit origin in Access-Control-Allow-Origin but omits Access-Control-Allow-Credentials: true.
Frontend Credentials Flag Set Unintentionally
The client application sets credentials: 'include' on public, unauthenticated endpoints that were intended for generic wildcard access.
Reverse Proxy Replaces Explicit Origin with Wildcard
An intermediate edge proxy or CDN overrides backend CORS response headers with a static wildcard origin.
What to check before changing code
- Check request credentials mode in frontend code: Verify whether the
fetchorXMLHttpRequestcall explicitly includescredentials: 'include'orwithCredentials = true. - Inspect response headers: Confirm whether the backend returned
Access-Control-Allow-Credentials: trueand an exact origin match rather than*. - Review origin allowlist logic: Ensure the backend validates the requesting origin against a trusted list before returning it.
How to verify the fix
Verify server responses using curl with a simulated origin:
curl -i -H "Origin: https://app.example.test" \
https://api.example.test/v1/user
Confirm that the response contains Access-Control-Allow-Origin: https://app.example.test and Access-Control-Allow-Credentials: true.
Key takeaway
When cross-origin requests include credentials, the browser rejects Access-Control-Allow-Origin: *. The server must validate the requesting origin against an internal allowlist, return the explicit origin string in Access-Control-Allow-Origin, and set Access-Control-Allow-Credentials: true.