CORS

CORS Error With credentials: include — Why * Stops Working

You added credentials: 'include' to your fetch call and now CORS is broken even though it worked before. The browser spec explicitly forbids wildcard origins when credentials are sent. Switch to an explicit origin.

Browser Console Error
Access to fetch at 'https://api.example.com' from origin 'https://app.example.com' has been blocked by CORS policy: 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 combination that breaks

// Frontend — sends cookies or auth headers
fetch('https://api.example.com/data', {
  credentials: 'include' // sends session cookie
});

// Backend — this breaks
app.use(cors({ origin: '*', credentials: true })); // ❌

The fix — explicit origin on every stack

Express

app.use(cors({
  origin: 'https://app.example.com', // not '*'
  credentials: true
}));

Nginx

add_header Access-Control-Allow-Origin "https://app.example.com" always;
add_header Access-Control-Allow-Credentials "true" always;
add_header Vary Origin always;

FastAPI

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://app.example.com"],  # not ["*"]
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

Multiple origins with credentials

// Express — dynamic origin from allowlist
const allowedOrigins = ['https://app.example.com', 'https://staging.example.com'];

app.use(cors({
  origin: function(origin, callback) {
    if (!origin || allowedOrigins.includes(origin)) {
      callback(null, origin); // return the actual origin, not '*'
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  credentials: true
}));

// Always add Vary: Origin so CDNs cache correctly
app.use((req, res, next) => { res.vary('Origin'); next(); });

Why Vary: Origin matters

When your server returns a specific origin in Access-Control-Allow-Origin (instead of *), CDNs might cache that response and serve it to users from other origins. Adding Vary: Origin tells the CDN to store separate cached responses for each origin — preventing one user's cookies from leaking to another.

Test your CORS credentials config →