CORS passes in Postman, passes preflight, fails with cookies: the credentials triangle
Problem
The API worked in Postman and from curl. The browser sent the preflight OPTIONS, got a 204, then failed on the actual request:
Access to fetch at 'https://api.example.com/me' from origin 'https://app.example.com' has been blocked by CORS policy: The value of 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.Adding credentials: 'include' to the fetch was the change that "broke" it — without cookies, the same request passed CORS fine.
Root cause
Three requirements must hold simultaneously for credentialed cross-origin requests, and the spec is strict about all three:
1. Access-Control-Allow-Origin must be the exact origin, never . 2. Access-Control-Allow-Credentials: true must be on the response. 3. Access-Control-Allow-Headers must name every custom header explicitly — is not honored for credentialed preflights.
Most CORS middleware defaults to * because that is what works for non-credentialed requests. One flag flip on the client and the entire configuration is invalid at once.
import cors from 'cors';
const ALLOWED = new Set(['https://app.example.com', 'https://staging.example.com']);
… 5 more lines in the fix🔒 the fix — including 3 code blocks — is members-only. $1/mo unlocks everything.