Fix: Credentials with Wildcard Origin Error

Diagnose and fix the common CORS error when using Access-Control-Allow-Credentials: true with Access-Control-Allow-Origin: *. Includes solutions for every major server framework.

Credentials

Detailed Explanation

The Problem

You see this error in the browser console:

Access to fetch at 'https://api.example.com/data' 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'.

This happens when the server sends:

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

Why It Fails

The CORS specification (Fetch Standard) explicitly forbids this combination. Allowing any origin to make credentialed requests would be a severe security hole — any website could steal session cookies.

The Fix

Replace the wildcard with the exact requesting origin. The server must read the Origin request header and echo it back (after validating it against an allowlist).

Fix for Express.js

const cors = require("cors");

const allowedOrigins = ["https://app.example.com"];

app.use(cors({
  origin: (origin, callback) => {
    if (!origin || allowedOrigins.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error("Not allowed by CORS"));
    }
  },
  credentials: true,
}));

Fix for Nginx

map $http_origin $cors_origin {
    default "";
    "https://app.example.com" "$http_origin";
}

add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Credentials "true" always;
add_header Vary Origin always;

Fix for Apache

SetEnvIf Origin "^https://app\.example\.com$" CORS_ORIGIN=$0
Header always set Access-Control-Allow-Origin "%{CORS_ORIGIN}e" env=CORS_ORIGIN
Header always set Access-Control-Allow-Credentials "true"
Header always set Vary "Origin"

Quick Checklist

  • Origin is not *
  • Origin matches the Origin request header exactly (including protocol and port)
  • Vary: Origin is present
  • Client sets credentials: "include"

Use Case

A developer adds credentials: true to their CORS middleware but forgets to change the origin from * to a specific domain. Everything works in Postman (which ignores CORS) but fails in the browser.

Try It — CORS Header Builder

Open full tool