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 withAccess-Control-Allow-Credentials: trueand must not use a wildcardAccess-Control-Allow-Origin: *. TheAccess-Control-Allow-Originheader 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: *withoutAccess-Control-Allow-Credentials: true— cookies are not sent, so no authenticated data theft. - The server validates the
Originagainst 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-Credentialscauses 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: trueis 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
Originheaders or use wildcard CORS with credentials, which may be exploitable.