
Misconfigured Access-Control-Allow-Credentials
What Does “Misconfigured Access-Control-Allow-Credentials” Mean?
The "Access-Control-Allow-Credentials"
header is used in Cross-Origin Resource Sharing (CORS) to allow the browser to send credentials (such as cookies, Authorization headers, or TLS client certificates) with cross-origin requests.
A misconfiguration occurs when:
- The server sets
Access-Control-Allow-Credentials: true
but does not properly configure CORS headers. - The
Access-Control-Allow-Origin
header is wildcard*
which is not allowed with credentials. - The browser blocks credentials due to incorrect request headers.
Common Causes & How to Fix Them
1. Using *
(Wildcard) with Credentials – NOT ALLOWED
Issue:
The following configuration is invalid and will result in a CORS error:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Browsers do not allow wildcard *
origins when Access-Control-Allow-Credentials: true
is set.
Fix:
Set a specific origin instead of: *
Access-Control-Allow-Origin: https://yourdomain.com
Access-Control-Allow-Credentials: true
For Express.js (Node.js):
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "https://yourdomain.com"); // No '*'
res.header("Access-Control-Allow-Credentials", "true");
next();
});
For Flask (Python):
@app.after_request
def add_cors_headers(response):
response.headers['Access-Control-Allow-Origin'] = 'https://yourdomain.com'
response.headers['Access-Control-Allow-Credentials'] = 'true'
return response
2. Credentials Not Sent from Client
Issue:
Even if the server allows credentials, the client must explicitly send them. If not, the browser will not include cookies, authorization headers, or TLS certificates.
Fix:
Ensure the client request includes credentials: "include"
in JavaScript:
Fetch API:
fetch("https://yourdomain.com/api", {
method: "GET",
credentials: "include", // Important!
})
.then((res) => res.json())
.then((data) => console.log(data))
.catch((err) => console.error(err));
Axios:
axios.get("https://yourdomain.com/api", { withCredentials: true })
.then(response => console.log(response.data))
.catch(error => console.error(error));
3. Preflight Requests Must Also Include Credentials
Issue:
If the request triggers a preflight request OPTIONS
the server must also allow credentials in the preflight response.
Fix:
Ensure preflight requests OPTIONS
method return the correct headers:
For Express.js:
app.options("*", (req, res) => {
res.header("Access-Control-Allow-Origin", "https://yourdomain.com");
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.send();
});
For Flask:
@app.route('/your-endpoint', methods=['OPTIONS'])
def handle_options():
response = jsonify()
response.headers['Access-Control-Allow-Origin'] = 'https://yourdomain.com'
response.headers['Access-Control-Allow-Credentials'] = 'true'
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
return response
4. Missing Vary: Origin
Header for Dynamic Origins
Issue:
If your API serves multiple frontends dynamically (e.g., allowing multiple origins), CORS may fail without the Vary: Origin
header.
Fix:
For dynamic origins, return the Vary: Origin
header to prevent caching issues:
For Express.js:
app.use((req, res, next) => {
const allowedOrigins = ["https://site1.com", "https://site2.com"];
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.header("Access-Control-Allow-Origin", origin);
res.header("Access-Control-Allow-Credentials", "true");
res.header("Vary", "Origin");
}
next();
});
For Flask:
@app.after_request
def add_cors_headers(response):
allowed_origins = ["https://site1.com", "https://site2.com"]
origin = request.headers.get("Origin")
if origin in allowed_origins:
response.headers["Access-Control-Allow-Origin"] = origin
response.headers["Access-Control-Allow-Credentials"] = "true"
response.headers["Vary"] = "Origin"
return response
Conclusion
The “Misconfigured Access-Control-Allow-Credentials” error is typically caused by:
- Using a wildcard origin
*
instead of a specific one. - Forgetting to send credentials from the client
credentials: "include"
- Missing preflight CORS headers.
- Not handling multiple origins correctly.