⚠️ Security-sensitive feature. This mode delegates authentication entirely to your reverse proxy. Misconfiguration can expose your Gateway to unauthorized access. Read this page carefully before enabling.
Use trusted-proxy auth mode when:
1008 unauthorized errors because browsers can’t pass tokens in WS payloadsx-forwarded-user: [email protected])gateway.trustedProxies){
gateway: {
// Must bind to network interface (not loopback)
bind: "lan",
// CRITICAL: Only add your proxy's IP(s) here
trustedProxies: ["10.0.0.1", "172.17.0.1"],
auth: {
mode: "trusted-proxy",
trustedProxy: {
// Header containing authenticated user identity (required)
userHeader: "x-forwarded-user",
// Optional: headers that MUST be present (proxy verification)
requiredHeaders: ["x-forwarded-proto", "x-forwarded-host"],
// Optional: restrict to specific users (empty = allow all)
allowUsers: ["[email protected]", "[email protected]"],
},
},
},
}
| Field | Required | Description |
|---|---|---|
gateway.trustedProxies |
Yes | Array of proxy IP addresses to trust. Requests from other IPs are rejected. |
gateway.auth.mode |
Yes | Must be "trusted-proxy" |
gateway.auth.trustedProxy.userHeader |
Yes | Header name containing the authenticated user identity |
gateway.auth.trustedProxy.requiredHeaders |
No | Additional headers that must be present for the request to be trusted |
gateway.auth.trustedProxy.allowUsers |
No | Allowlist of user identities. Empty means allow all authenticated users. |
Pomerium passes identity in x-pomerium-claim-email (or other claim headers) and a JWT in x-pomerium-jwt-assertion.
{
gateway: {
bind: "lan",
trustedProxies: ["10.0.0.1"], // Pomerium's IP
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-pomerium-claim-email",
requiredHeaders: ["x-pomerium-jwt-assertion"],
},
},
},
}
Pomerium config snippet:
routes:
- from: https://coderclaw.example.com
to: http://coderclaw-gateway:18789
policy:
- allow:
or:
- email:
is: [email protected]
pass_identity_headers: true
Caddy with the caddy-security plugin can authenticate users and pass identity headers.
{
gateway: {
bind: "lan",
trustedProxies: ["127.0.0.1"], // Caddy's IP (if on same host)
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-forwarded-user",
},
},
},
}
Caddyfile snippet:
coderclaw.example.com {
authenticate with oauth2_provider
authorize with policy1
reverse_proxy coderclaw:18789 {
header_up X-Forwarded-User {http.auth.user.email}
}
}
oauth2-proxy authenticates users and passes identity in x-auth-request-email.
{
gateway: {
bind: "lan",
trustedProxies: ["10.0.0.1"], // nginx/oauth2-proxy IP
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-auth-request-email",
},
},
},
}
nginx config snippet:
location / {
auth_request /oauth2/auth;
auth_request_set $user $upstream_http_x_auth_request_email;
proxy_pass http://coderclaw:18789;
proxy_set_header X-Auth-Request-Email $user;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
{
gateway: {
bind: "lan",
trustedProxies: ["172.17.0.1"], // Traefik container IP
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-forwarded-user",
},
},
},
}
Before enabling trusted-proxy auth, verify:
x-forwarded-* headers from clientscoderclaw security audit will flag trusted-proxy auth with a critical severity finding. This is intentional — it’s a reminder that you’re delegating security to your proxy setup.
The audit checks for:
trustedProxies configurationuserHeader configurationallowUsers (allows any authenticated user)The request didn’t come from an IP in gateway.trustedProxies. Check:
docker inspect or kubectl get pods -o wide to find actual IPsThe user header was empty or missing. Check:
A required header wasn’t present. Check:
The user is authenticated but not in allowUsers. Either add them or remove the allowlist.
Make sure your proxy:
Upgrade: websocket, Connection: upgrade)If you’re moving from token auth to trusted-proxy:
coderclaw security audit and review findings