Wildcard Not Allowed for Access-Control-Allow-Headers

Wildcard Not Allowed for Access-Control-Allow-Headers

What Does This Error Mean?

The Access-Control-Allow-Headers response header in CORS (Cross-Origin Resource Sharing) specifies which HTTP headers are allowed in cross-origin requests.

Unlike Access-Control-Allow-Origin, you cannot use a wildcard (*) in Access-Control-Allow-Headers if the request includes credentials (withCredentials: true in JavaScript).

This error occurs when:

  • The server sets Access-Control-Allow-Headers: *, but the request includes credentials (cookies, Authorization tokens, etc.).
  • A proxy (e.g., Nginx, API Gateway) misconfigures CORS headers.
  • The preflight request (OPTIONS method) does not properly return allowed headers.

How to Fix It

1. Explicitly Define Allowed Headers

๐Ÿ” Issue:
Browsers block Access-Control-Allow-Headers: * when credentials (withCredentials: true) are used.

โœ… Fix:
List all required headers explicitly instead of using *.

For Express.js (Node.js):

app.use((req, res, next) => {
  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.header("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With"); 
  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'
    response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
    response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, X-Requested-With'
    return response

2. Ensure Preflight (OPTIONS) Requests Are Handled

๐Ÿ” Issue:
When a client sends a request with custom headers (Authorization, Content-Type), the browser first sends an OPTIONS preflight request. If the server does not correctly respond, the request fails.

โœ… Fix:
Handle OPTIONS requests properly.

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.header("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
  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'
    response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, X-Requested-With'
    return response

3. Fix Client-Side Requests

๐Ÿ” Issue:
The client must match the allowed headers set on the server.

โœ… Fix:
Ensure the frontend does not request a wildcard (*) and sends only the necessary headers.

Fetch API:

fetch("https://yourdomain.com/api", {
  method: "POST",
  credentials: "include", // Enables cookies or authentication headers
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer YOUR_TOKEN",
  },
  body: JSON.stringify({ key: "value" }),
});

Axios:

axios.post("https://yourdomain.com/api", 
  { key: "value" }, 
  { headers: { "Content-Type": "application/json", "Authorization": "Bearer YOUR_TOKEN" }, withCredentials: true }
);

4. Allow Dynamic Headers Without Wildcard

๐Ÿ” Issue:
If your API needs to support multiple frontends, manually listing all headers may be difficult.

โœ… Fix:
Use Vary: Access-Control-Request-Headers to allow dynamic headers.

For Express.js:

app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", req.headers.origin || "https://yourdomain.com");
  res.header("Access-Control-Allow-Credentials", "true");
  res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
  res.header("Access-Control-Allow-Headers", req.headers["access-control-request-headers"] || "Content-Type, Authorization");
  res.header("Vary", "Access-Control-Request-Headers");
  next();
});

For Flask:

@app.after_request
def add_cors_headers(response):
    request_headers = request.headers.get("Access-Control-Request-Headers")
    if request_headers:
        response.headers["Access-Control-Allow-Headers"] = request_headers
        response.headers["Vary"] = "Access-Control-Request-Headers"
    return response

Conclusion

The โ€œWildcard Not Allowed for Access-Control-Allow-Headersโ€ error happens because:

  • Wildcards (*) are not allowed when credentials (withCredentials: true) are used.
  • The server must explicitly list allowed headers in Access-Control-Allow-Headers.
  • The preflight request (OPTIONS) must be correctly handled.