Skip to content

Access-Control-Allow-Credentials — Handling Cookies and Auth in Cross-Origin Requests

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Access. We cover key concepts, practical examples, and best practices to help you master this topic.

The Access-Control-Allow-Credentials header tells the browser that the server permits credentials such as cookies, authorization headers, or TLS client certificates to be included in cross-origin requests.

What You'll Learn

  • When and why to use credentials with CORS
  • Restrictions when using credentials with CORS
  • How to configure credentials on client and server

Why It Matters

Many APIs require session cookies or authentication tokens. Without credentials support, users must re-authenticate for every cross-origin request. Doda Browser's authenticated API uses credentialed CORS to maintain session state across its web interface and browser extension.

flowchart TD
    A["Client sets credentials: 'include'"] --> B["Browser adds credentials to request"]
    B --> C{"Server response has ACAO = specific origin?"}
    C -->|"Yes"| D{"ACAO is not *?"}
    D -->|"Yes"| E{"ACAC is true?"}
    E -->|"Yes"| F["Response exposed to JS"]
    C -->|"No"| G["Blocked: no ACAO"]
    D -->|"No, ACAO = *"| H["Blocked: wildcard with credentials"]
    E -->|"No"| I["Blocked: credentials not allowed"]
    style F fill:#86efac,stroke:#16a34a
    style G fill:#fecaca,stroke:#dc2626
    style H fill:#fecaca,stroke:#dc2626
    style I fill:#fecaca,stroke:#dc2626

Code Examples

// Client-side: include credentials with fetch
fetch('https://api.example.com/user/profile', {
  method: 'GET',
  credentials: 'include' // Send cookies cross-origin
}).then(response => {
  return response.json();
});

// With XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/user/profile', true);
xhr.withCredentials = true;
xhr.send();
# Flask server allowing credentialed requests
@app.after_request
def handle_credentials(response):
    origin = request.headers.get('Origin')
    if origin in ALLOWED_ORIGINS:
        # Must be specific origin, not *
        response.headers['Access-Control-Allow-Origin'] = origin
        response.headers['Access-Control-Allow-Credentials'] = 'true'
        response.headers['Vary'] = 'Origin'
    return response
// Express with credentials support
const cors = require('cors');
const corsOptions = {
  origin: ['https://app.example.com', 'https://admin.example.com'],
  credentials: true,  // Allow cookies/auth headers
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization']
};
app.use(cors(corsOptions));
# Test credentialed CORS
curl -I -H "Origin: https://app.example.com" \
  -H "Cookie: session=abc123" \
  https://api.example.com/profile | grep -i "access-control"

Common Mistakes

1. Setting Allow-Origin to * with Credentials

The browser blocks the response if Allow-Origin is * and Allow-Credentials is true.

2. Forgetting to Set withCredentials on the Client

If the client does not set credentials: include, no cookies are sent even if the server allows them.

3. Omitting the Vary: Origin Header

Without Vary: Origin, cached responses with credentials may be served to the wrong origin.

4. Using Credentials with CDN-Cached Endpoints

CDN Caching breaks credentialed requests. Use Cache-Control: private for credentialed responses.

5. Allowing Credentials on Wildcard Subdomain Origins

A dynamic origin that matches *.example.com must be exact, not a pattern. Validate the specific origin.

Practice Questions

  1. What does Access-Control-Allow-Credentials: true enable?
  2. Why can't you use * for Allow-Origin with credentials?
  3. What client-side fetch option sends cookies cross-origin?
  4. What Vary header should you set with credentialed CORS?
  5. Can credentialed CORS work with public CDN caching?

Answers:

  1. It allows the browser to include cookies, auth headers, and client certificates.
  2. The wildcard means any origin is allowed, which is incompatible with the security model of credentialed requests.
  3. credentials: 'include'.
  4. Vary: Origin.
  5. No. Credentialed responses must use Cache-Control: private or no-cache.

Challenge: Set up a full-stack application with a frontend on localhost:3000 and an API on localhost:3001. Implement login on the API, send session cookies via credentialed CORS, and verify the session persists across requests.

FAQ

Does Access-Control-Allow-Credentials work with all fetch modes?

No. It works with cors mode (the default for same-origin). In no-cors mode, the response is opaque and credentials are never sent.

Can I use Access-Control-Allow-Credentials with the wildcard * for methods or headers?

No. When Allow-Credentials is true, Allow-Origin must be a specific origin. The wildcard * for methods and headers is also not permitted.

How does credentialed CORS interact with cross-origin redirects?

The browser checks CORS headers on each redirect response. The origin must be allowed on every response in the redirect chain.

Does credentialed CORS send cookies to third-party domains?

Yes. That is why it requires explicit server opt-in. The SameSite cookie attribute also affects whether cookies are sent cross-origin.

What happens to the Set-Cookie header in credentialed CORS?

The browser processes Set-Cookie headers from cross-origin responses when credentials are included. This enables cross-origin session management.

Mini Project

Build a cross-origin authentication system: a login page on one origin that authenticates against an API on another origin. Use credentialed CORS to send and receive session cookies. Implement CSRF protection using the SameSite attribute and the state parameter. Test the complete login flow with browser developer tools.

What's Next

Optimize preflight performance with Access-Control-Max-Age, then explore the wildcard and credentials conflict in detail.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro