- Home
- HTTP Headers
- Access-Control-Allow-Credentials Header
Header
Access-Control-Allow-Credentials Header
Learn how Access-Control-Allow-Credentials controls whether browsers expose responses when credentials (cookies, auth headers) are included in CORS requests.
TL;DR: Allows cross-origin requests to include credentials (cookies, auth headers). Set to
trueto enable, requires specific origin (not wildcard).
What is Access-Control-Allow-Credentials?
The Access-Control-Allow-Credentials header indicates whether the browser should expose the response to frontend JavaScript when the request includes credentials (cookies, authorization headers, or TLS client certificates).
This header is a critical part of CORS (Cross-Origin Resource Sharing) security. When set to true, it tells the browser: “Yes, you can share this response with the JavaScript code, even though credentials were included in the cross-origin request.”
How Access-Control-Allow-Credentials Works
Request with credentials:
GET /api/user HTTP/1.1
Host: api.example.com
Origin: https://app.example.com
Cookie: session=abc123
```text
**Server allows credentials:**
```http
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://app.example.com
{"username": "john", "email": "john@example.com"}
Syntax
Access-Control-Allow-Credentials: true
```text
The only valid value is `true`. If credentials should not be allowed, omit the header entirely.
```http
# ✅ Allow credentials
Access-Control-Allow-Credentials: true
# ❌ Invalid - don't use false
Access-Control-Allow-Credentials: false
# ✅ Don't allow credentials - omit the header
# (no Access-Control-Allow-Credentials header)
Common Examples
API with Cookie Authentication
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://app.example.com
Set-Cookie: session=xyz789; Secure; HttpOnly; SameSite=None
{"status": "authenticated"}
```http
### Preflight Response for Credentialed Request
```http
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
Without Credentials (Header Omitted)
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json
{"data": "public"}
```javascript
## Real-World Scenarios
### Single-Page Application with Session Cookies
**Client-side fetch with credentials:**
```javascript
fetch('https://api.example.com/user/profile', {
method: 'GET',
credentials: 'include', // Send cookies
headers: {
'Content-Type': 'application/json'
}
})
.then((response) => response.json())
.then((data) => console.log(data))
Server response:
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://app.example.com
Content-Type: application/json
{"id": 123, "name": "John Doe"}
```text
### OAuth/Bearer Token Authentication
**Request with Authorization header:**
```javascript
fetch('https://api.example.com/protected', {
method: 'POST',
credentials: 'include',
headers: {
Authorization: 'Bearer eyJhbGc...',
'Content-Type': 'application/json'
},
body: JSON.stringify({ data: 'value' })
})
Server response:
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://app.example.com
Content-Type: application/json
{"success": true}
```http
### Microservices with Shared Authentication
**Request between frontend and microservice:**
```http
POST /api/orders HTTP/1.1
Host: orders.example.com
Origin: https://shop.example.com
Cookie: auth_token=secret123
Content-Type: application/json
Microservice response:
HTTP/1.1 201 Created
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://shop.example.com
Content-Type: application/json
{"orderId": "ORD-001", "status": "created"}
```text
## Security Considerations
### Cannot Use Wildcard Origin
When `Access-Control-Allow-Credentials: true` is set, you **cannot** use `Access-Control-Allow-Origin: *`:
```http
# ❌ INVALID - Browser will reject this
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
# ✅ VALID - Specific origin required
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://app.example.com
```javascript
### Dynamic Origin Validation
```javascript
// Node.js/Express example
app.use((req, res, next) => {
const allowedOrigins = ['https://app.example.com', 'https://admin.example.com']
const origin = req.headers.origin
if (allowedOrigins.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin)
res.setHeader('Access-Control-Allow-Credentials', 'true')
}
next()
})
Cookie Security Requirements
When using credentials, ensure cookies are properly secured:
Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=None
```javascript
- `Secure`: Only sent over HTTPS
- `HttpOnly`: Not accessible via JavaScript
- `SameSite=None`: Required for cross-site cookies
## Best Practices
### 1. Use Specific Origins
```javascript
// ❌ Too permissive
res.setHeader('Access-Control-Allow-Origin', '*')
res.setHeader('Access-Control-Allow-Credentials', 'true') // Won't work!
// ✅ Specific and secure
const allowedOrigins = ['https://app.example.com']
if (allowedOrigins.includes(req.headers.origin)) {
res.setHeader('Access-Control-Allow-Origin', req.headers.origin)
res.setHeader('Access-Control-Allow-Credentials', 'true')
}
2. Validate Origins Carefully
// ❌ Vulnerable to subdomain attacks
const origin = req.headers.origin
if (origin.endsWith('.example.com')) {
res.setHeader('Access-Control-Allow-Origin', origin)
res.setHeader('Access-Control-Allow-Credentials', 'true')
}
// ✅ Use explicit allowlist
const allowedOrigins = new Set(['https://app.example.com', 'https://admin.example.com'])
if (allowedOrigins.has(req.headers.origin)) {
res.setHeader('Access-Control-Allow-Origin', req.headers.origin)
res.setHeader('Access-Control-Allow-Credentials', 'true')
}
```http
### 3. Combine with Other Security Headers
```http
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://app.example.com
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Content-Security-Policy: default-src 'self'
4. Handle Preflight Requests
// Express middleware
app.options('/api/*', (req, res) => {
const allowedOrigins = ['https://app.example.com']
if (allowedOrigins.includes(req.headers.origin)) {
res.setHeader('Access-Control-Allow-Origin', req.headers.origin)
res.setHeader('Access-Control-Allow-Credentials', 'true')
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE')
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')
res.setHeader('Access-Control-Max-Age', '86400')
}
res.sendStatus(204)
})
```text
## Common Errors and Solutions
### Error: Wildcard with Credentials
```text
Access to fetch at 'https://api.example.com' 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'.
```text
**Solution:**
```javascript
// Change from wildcard to specific origin
res.setHeader('Access-Control-Allow-Origin', req.headers.origin)
res.setHeader('Access-Control-Allow-Credentials', 'true')
Error: Missing Credentials Header
Access to fetch at 'https://api.example.com' from origin 'https://app.example.com'
has been blocked by CORS policy: The value of the 'Access-Control-Allow-Credentials'
header in the response is '' which must be 'true' when the request's credentials mode is 'include'.
Solution:
res.setHeader('Access-Control-Allow-Credentials', 'true')
```text
## Testing
### Using curl
```bash
# Test with credentials
curl -X GET https://api.example.com/user \
-H "Origin: https://app.example.com" \
-H "Cookie: session=abc123" \
-v
# Check preflight
curl -X OPTIONS https://api.example.com/user \
-H "Origin: https://app.example.com" \
-H "Access-Control-Request-Method: POST" \
-v
Using JavaScript
// Test credentialed request
fetch('https://api.example.com/user', {
method: 'GET',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
}
})
.then((response) => {
console.log('CORS headers:', {
allowCredentials: response.headers.get('Access-Control-Allow-Credentials'),
allowOrigin: response.headers.get('Access-Control-Allow-Origin')
})
return response.json()
})
.then((data) => console.log(data))
.catch((error) => console.error('CORS error:', error))
Related Headers
- Access-Control-Allow-Origin - Allowed origins
- Access-Control-Allow-Methods - Allowed HTTP methods
- Access-Control-Allow-Headers - Allowed request headers
- Access-Control-Max-Age - Preflight cache duration
- Origin - Request origin
Security Risks of Credentials: true
Enabling Access-Control-Allow-Credentials: true significantly increases the attack surface of your API. With credentials enabled, a cross-origin request from a malicious site can include the victim’s cookies, potentially allowing the attacker to make authenticated requests on the victim’s behalf. This is why the browser enforces that Access-Control-Allow-Origin must be a specific origin (not *) when credentials are enabled.
The risk is highest for APIs that use cookie-based authentication and allow credentials from multiple origins. Each allowed origin is a potential attack vector if that origin is ever compromised. Minimize the number of origins in your allowlist, and consider whether cross-origin credential sharing is truly necessary or whether a same-origin architecture (serving the frontend and API from the same domain) would eliminate the need for credentialed CORS entirely.
Frequently Asked Questions
What is Access-Control-Allow-Credentials?
This header allows cross-origin requests to include credentials (cookies, authorization headers). Set to true to enable. Without it, browsers strip credentials from cross-origin requests.
Can I use credentials with wildcard origin?
No. When Access-Control-Allow-Credentials is true, Access-Control-Allow-Origin must be a specific origin, not *. This prevents credential leakage to arbitrary sites.
How do I send cookies cross-origin?
Server must send Access-Control-Allow-Credentials: true with specific origin. Client must set credentials: include in fetch or withCredentials: true in XMLHttpRequest.
Why are my cookies not being sent?
Check: 1) Server sends Allow-Credentials: true, 2) Origin is specific not *, 3) Client sets credentials mode, 4) Cookie SameSite allows cross-site, 5) Cookie Secure if HTTPS.