Cybersecurity / Networking

API Key Header Stripped by Reverse Proxy or Load Balancer

· by DebuggedIt

Quick answer

An API key that's correctly sent by the client but never actually reaches your backend application usually means an intermediate layer — a reverse proxy, load...

An API key that's correctly sent by the client but never actually reaches your backend application usually means an intermediate layer — a reverse proxy, load balancer, or CDN — is stripping it, whether due to a default security configuration, a header allowlist that doesn't include your custom header, or a caching layer that doesn't forward all headers by default.

The Problem

A request that includes an API key or authorization header works fine when tested directly against the backend, but fails with an authentication error when made through the normal, full request path:

# Direct to backend - works
curl -H "X-API-Key: secret123" http://backend-server:3000/data

# Through the full public path - fails as if the header was never sent
curl -H "X-API-Key: secret123" https://api.example.com/data
# 401 Unauthorized

Why It Happens

Several distinct intermediate layers can strip headers, each for different underlying reasons:

  • Some reverse proxies and load balancers only forward a specific, configured allowlist of headers by default, and a custom header name (like a non-standard X-API-Key) isn't automatically included unless explicitly configured to be passed through
  • A CDN with caching enabled might strip certain headers before caching or forwarding a request, particularly if that specific header isn't part of its cache key configuration and the CDN's default behavior is to normalize/strip headers it doesn't specifically need for its own caching logic
  • A security-focused proxy or WAF might specifically strip headers matching certain patterns as a security measure, sometimes overly broadly, inadvertently catching legitimate application headers that happen to match a filtering rule intended for something else entirely
  • Case sensitivity or exact-name matching issues, where an intermediate layer's own header-forwarding configuration expects a specific exact header name that doesn't quite match what your client is actually sending

The Fix

First, isolate exactly which hop in the request's path is stripping the header, testing progressively from the backend outward toward the public-facing edge, similar to the general layered-diagnosis approach useful for several proxy-related header issues:

# Test each layer independently, if you have access to do so
curl -H "X-API-Key: secret123" http://backend-directly:3000/data
curl -H "X-API-Key: secret123" http://reverse-proxy-directly/data
curl -H "X-API-Key: secret123" https://cdn-or-full-path/data

Comparing where the header genuinely stops being forwarded pinpoints exactly which specific layer needs configuration, rather than guessing based on which layer seems most likely.

For Nginx specifically, confirm you're not accidentally clearing the header somewhere in your configuration — while Nginx doesn't strip custom headers by default, an explicit configuration mistake (like an unintentional proxy_set_header X-API-Key "";, which explicitly clears a header) can produce exactly this symptom:

grep -r "X-API-Key" /etc/nginx/

If you find an explicit clearing directive that shouldn't be there, remove it, and confirm the header is instead correctly passed through (which is Nginx's actual default behavior for headers not explicitly modified) or, if you do need explicit control, forward it deliberately:

location /api/ {
    proxy_pass http://backend;
    proxy_set_header X-API-Key $http_x_api_key;
}

For a CDN or managed load balancer, check that platform's own documentation and dashboard configuration for header forwarding rules — many CDNs specifically require custom headers to be explicitly allowlisted for forwarding, especially if the CDN's caching is also enabled, since headers not part of the cache key configuration are sometimes stripped by default as part of normalizing what gets cached and served from cache versus what varies per-request.

If a WAF or security proxy layer is confirmed as the source, review its specific header-filtering rules for anything that might be unintentionally matching your API key header's name or pattern — security tools sometimes have broad default rules (like stripping anything matching common "sensitive header" naming patterns) that can inadvertently catch legitimate custom authentication headers using similar naming conventions.

As a general best practice regardless of the specific cause, use the standard Authorization header (with an appropriate scheme, like Bearer) rather than a custom header name where practical, since standard headers are much more reliably and predictably forwarded by default across the wide range of proxies, CDNs, and load balancers you might encounter, compared to arbitrary custom header names that different tools handle inconsistently:

curl -H "Authorization: Bearer secret123" https://api.example.com/data

Still Not Working?

If you've confirmed and fixed forwarding at every layer you have direct configuration access to, but the header still doesn't reach your backend, check whether there's an additional layer in the request path you weren't initially aware of — some managed cloud infrastructure includes additional, less visible proxying layers (an API gateway service, a managed ingress controller) that aren't obvious from your own application-level configuration, and reviewing your cloud provider's or platform's full architecture documentation for your specific deployment can reveal an additional hop worth testing independently that wasn't part of your original mental model of the request's actual path.