Configure Credentialed CORS without Wildcard Origins

A browser request that includes cookies or HTTP authentication cannot use Access-Control-Allow-Origin: *. The server must approve the requesting origin explicitly and return Access-Control-Allow-Credentials: true only for that trusted origin.

Last updated: November 11, 2026.

const allowedOrigins = new Set([
  'https://app.example.com',
  'https://admin.example.com',
]);

function corsHeaders(requestOrigin) {
  if (!allowedOrigins.has(requestOrigin)) return {};

  return {
    'Access-Control-Allow-Origin': requestOrigin,
    'Access-Control-Allow-Credentials': 'true',
    'Vary': 'Origin',
  };
}

fetch('https://api.example.com/account', {
  credentials: 'include',
});

Apply these response headers before sending the API response. Reject an unapproved origin instead of reflecting it, and handle preflight requests with the same allowlist decision.

Match the origin exactly

The MDN CORS guide defines an origin by scheme, host, and port. Store complete origins such as https://app.example.com; do not accept a value merely because it ends with a trusted domain. That loose comparison can allow an attacker-controlled host such as example.com.attacker.test.

The browser sends an Origin header. Compare it with the allowlist, then return the exact approved value. If responses vary by origin, Vary: Origin prevents a shared cache from serving one tenant or site a response prepared for another origin.

Enable credentials deliberately

The Access-Control-Allow-Credentials reference documents true as the only valid value. When credentials are not allowed, omit the header rather than sending false. Client code must also opt in with credentials: "include" for cross-origin fetch() requests.

For non-simple requests, answer the browser’s OPTIONS preflight with the approved origin, methods, headers, and credential setting. Do not require the application request body on that preflight. Cookie SameSite and Secure attributes still determine whether a cross-site cookie is sent.

CORS controls whether browser JavaScript may read a response; it is not authentication or CSRF protection. Continue checking the user session, authorization, CSRF defenses, and request content type. Keep the allowlist small, use HTTPS, and avoid enabling credentialed CORS for endpoints that do not require cross-origin browser access.

Related Web Cheat Sheet guides

Sergey Kornilov

Sergey Kornilov