Using fetch with Credentials in JavaScript

When you call an API from JavaScript, the browser's fetch API does not automatically send cookies or HTTP authentication headers (like Authorization or Basic). You control this with the credentials option.

The credentials Option

fetch("https://api.example.com/private", {
  method: "GET",
  credentials: "include"   // send cookies + auth headers even cross-origin
})
  .then(r => r.json())
  .then(data => console.log(data))
  .catch(err => console.error(err));
Value Behavior
"omit" Never send cookies or auth headers.
"same-origin" (default) Send credentials only if the request is to the same origin as the page.
"include" Always send credentials, even for cross-origin requests.

CORS requirement: When using credentials: "include", the server must respond with Access-Control-Allow-Credentials: true and must not use a wildcard Access-Control-Allow-Origin: *. The Access-Control-Allow-Origin header must echo the exact origin.

Sending Bearer Tokens

For APIs that use token-based auth, attach the Authorization header manually:

fetch("https://api.example.com/private", {
  method: "GET",
  headers: {
    "Authorization": "Bearer " + token
  }
});

If the token comes from an HttpOnly cookie, you cannot read it from JavaScript; instead rely on credentials: "include" so the browser sends the cookie automatically.

CORS Misconfiguration: Wildcard Origin + Credentials

A dangerous pattern is when an API server attempts to be "open" by dynamically echoing the request's Origin header:

Access-Control-Allow-Origin: https://attacker.com
Access-Control-Allow-Credentials: true

This is effectively equivalent to allowing any origin. If the API uses cookie-based authentication, an attacker-controlled site can trick the victim's browser into sending authenticated requests to the API and reading the response.

Why this works even when the static site has no cookies

The victim's browser already has session cookies for the API server. The attacker only needs to lure the victim to a malicious static site. The malicious JavaScript then calls the API with credentials: "include", and the browser sends the API cookies automatically. If the API reflects the attacker's origin and allows credentials, it returns the private data to the attacker.

// Running on https://attacker.com
fetch("https://api.victim.com/private", { credentials: "include" })
  .then(r => r.json())
  .then(data => exfiltrate(data));

This is a form of Cross-Origin Resource Sharing (CORS) misconfiguration and can lead to account takeover, data theft, or privilege escalation depending on the API endpoints exposed.

When this is NOT vulnerable

  • The API does not use cookie-based sessions (e.g., it requires a token in a header that the attacker cannot guess).
  • The server uses Access-Control-Allow-Origin: * without Access-Control-Allow-Credentials: true — cookies are not sent, so no authenticated data theft.
  • The server validates the Origin against an explicit allowlist and rejects unknown origins.

Security Pitfalls

  • Hard-coded tokens in client-side code leak to anyone who views the source.
  • credentials: "include" to untrusted APIs exposes session cookies; always verify the endpoint and CORS policy.
  • Missing Access-Control-Allow-Credentials causes the browser to block the response, even though the request is sent.
  • Mixing HTTP/HTTPS on a page with credentials can leak auth data via mixed-content or downgrade attacks.
  • Dynamically reflecting the Origin header to allow arbitrary origins combined with Access-Control-Allow-Credentials: true is a critical vulnerability.

Python Pentest Relevance

When building recon tools, HTTP Automation and Web Scraping scripts often hit the same APIs. Understanding fetch credentials helps you:

  • Reverse-engineer how a front-end authenticates to its back-end.
  • Identify session-management weaknesses during CORS misconfiguration tests.
  • Build scraping tools that replicate browser behavior, including cookie and token handling.
  • Detect APIs that echo Origin headers or use wildcard CORS with credentials, which may be exploitable.