Configure OpenClaw Trusted Proxy Auth for Secure Access
Managing authentication can feel like a chore, especially when you already have a solid identity provider sitting in front of your stack. If you’ve ever struggled with WebSocket connection errors or felt the friction of managing separate tokens for every single internal tool, you’re in the right place.
Trusted Proxy Auth lets you hand off the heavy lifting of identity verification to your reverse proxy. It’s a great way to keep your setup clean, but because it’s a security-sensitive feature, you need to get the details right.
When to Use
Section titled “When to Use”You should consider the trusted-proxy auth mode if:
- You run OpenClaw behind an identity-aware proxy like Pomerium, Caddy with OAuth, nginx with oauth2-proxy, or Traefik with forward auth.
- Your proxy handles all authentication and passes user identity through headers.
- You’re in a Kubernetes or container environment where the proxy is the only way to reach the Gateway.
- You’re seeing WebSocket
1008 unauthorizederrors because browsers can’t pass tokens in WebSocket payloads.
When NOT to Use
Section titled “When NOT to Use”Avoid this mode if:
- Your proxy doesn’t actually authenticate users and just handles TLS or load balancing.
- There is any way to reach the Gateway that bypasses the proxy, such as firewall holes or direct internal network access.
- You aren’t sure if your proxy correctly strips or overwrites forwarded headers from clients.
- You only need personal single-user access; in that case, Tailscale Serve with loopback is often a simpler choice.
How It Works
Section titled “How It Works”The process is straightforward:
- Your reverse proxy authenticates users via OAuth, OIDC, SAML, or another method.
- The proxy adds a header containing the authenticated user identity (like
x-forwarded-user: nick@example.com). - OpenClaw checks that the request came from a trusted proxy IP defined in your config.
- OpenClaw pulls the user identity from the specific header you configured.
- If the IP and headers check out, the request is authorized.
Control UI Pairing Behavior
Section titled “Control UI Pairing Behavior”When you activate gateway.auth.mode = "trusted-proxy" and a request passes the checks, Control UI WebSocket sessions can connect without needing a device pairing identity.
This has a few important effects:
- Pairing is no longer the main gate for Control UI access.
- Your reverse proxy auth policy and the
allowUserslist become your primary access controls. - You must keep gateway ingress locked down to trusted proxy IPs only using
gateway.trustedProxiesand your firewall.
Configuration
Section titled “Configuration”{ gateway: { // Use loopback for same-host proxy setups; use lan/custom for remote proxy hosts bind: "loopback",
// 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: ["nick@example.com", "admin@company.org"], }, }, },}If your gateway.bind is set to loopback, make sure to include a loopback proxy address in gateway.trustedProxies (like 127.0.0.1, ::1, or an equivalent CIDR).
Configuration Reference
Section titled “Configuration Reference”| 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. |
TLS termination and HSTS
Section titled “TLS termination and HSTS”I recommend using one TLS termination point and applying HSTS there.
Recommended pattern: proxy TLS termination
Section titled “Recommended pattern: proxy TLS termination”When your reverse proxy handles HTTPS for https://control.example.com, you should set Strict-Transport-Security at the proxy for that domain.
- This is a good fit for internet-facing deployments.
- It keeps your certificate and HTTP hardening policy in one spot.
- OpenClaw can stay on loopback HTTP behind the proxy.
Example header value:
Strict-Transport-Security: max-age=31536000; includeSubDomainsGateway TLS termination
Section titled “Gateway TLS termination”If OpenClaw serves HTTPS directly without a TLS-terminating proxy, use this config:
{ gateway: { tls: { enabled: true }, http: { securityHeaders: { strictTransportSecurity: "max-age=31536000; includeSubDomains", }, }, },}The strictTransportSecurity field takes a string header value. You can also set it to false to disable it explicitly.
Rollout guidance
Section titled “Rollout guidance”- Start with a short max age like
max-age=300while you validate traffic. - Only increase to long-lived values like
max-age=31536000once you are confident. - Only add
includeSubDomainsif every subdomain is ready for HTTPS. - Use preload only if you intend to meet the requirements for your full domain set.
- Local development on loopback doesn’t need HSTS.
Proxy Setup Examples
Section titled “Proxy Setup Examples”Pomerium
Section titled “Pomerium”Pomerium passes identity in x-pomerium-claim-email 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://openclaw.example.com to: http://openclaw-gateway:18789 policy: - allow: or: - email: is: nick@example.com pass_identity_headers: trueCaddy with OAuth
Section titled “Caddy with OAuth”Caddy with the caddy-security plugin can handle authentication 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:
openclaw.example.com { authenticate with oauth2_provider authorize with policy1
reverse_proxy openclaw:18789 { header_up X-Forwarded-User {http.auth.user.email} }}nginx + oauth2-proxy
Section titled “nginx + oauth2-proxy”In this setup, 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://openclaw: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";}Traefik with Forward Auth
Section titled “Traefik with Forward Auth”{ gateway: { bind: "lan", trustedProxies: ["172.17.0.1"], // Traefik container IP auth: { mode: "trusted-proxy", trustedProxy: { userHeader: "x-forwarded-user", }, }, },}Mixed token configuration
Section titled “Mixed token configuration”OpenClaw will reject configurations where both a gateway.auth.token (or OPENCLAW_GATEWAY_TOKEN) and trusted-proxy mode are active. This prevents loopback requests from accidentally using the wrong authentication path.
If you run into a mixed_trusted_proxy_token error:
- Remove the shared token if you want to use trusted-proxy mode.
- Switch
gateway.auth.modeto"token"if you prefer token-based auth.
Loopback trusted-proxy auth is designed to fail closed. Callers on the same host must provide the configured identity headers through a trusted proxy rather than being authenticated automatically.
Security Checklist
Section titled “Security Checklist”Before you flip the switch on trusted-proxy auth, verify these points:
- Proxy is the only path: Your Gateway port is firewalled from everything except your proxy.
- trustedProxies is minimal: You only listed actual proxy IPs, not broad subnets.
- Proxy strips headers: Your proxy overwrites
x-forwarded-*headers from clients instead of just appending to them. - TLS termination: Your proxy handles TLS so users connect via HTTPS.
- allowUsers is set: It is safer to restrict access to known users rather than allowing anyone who is authenticated.
- No mixed token config: You haven’t set both
gateway.auth.tokenandgateway.auth.mode: "trusted-proxy".
Security Audit
Section titled “Security Audit”Running openclaw security audit will show a critical severity finding for trusted-proxy auth. This is by design to remind you that security depends on your proxy setup.
The audit looks for:
- Missing
trustedProxiessettings. - Missing
userHeadersettings. - An empty
allowUserslist (which lets any authenticated user in).
Troubleshooting
Section titled “Troubleshooting””trusted_proxy_untrusted_source”
Section titled “”trusted_proxy_untrusted_source””This means the request came from an IP not listed in gateway.trustedProxies.
- Check if the proxy IP is correct (Docker container IPs change often).
- See if there is a load balancer in front of your proxy.
- Use
docker inspectorkubectl get pods -o wideto find the real IPs.
”trusted_proxy_user_missing”
Section titled “”trusted_proxy_user_missing””The user header was empty or not there at all.
- Verify your proxy is configured to pass identity headers.
- Check that the header name is spelled correctly.
- Ensure the user is actually authenticated at the proxy level.
”trusted_proxy_missing_header_*”
Section titled “”trusted_proxy_missing_header_*””A required header was missing.
- Check your proxy config for those specific headers.
- Look for anything in the chain that might be stripping headers.
”trusted_proxy_user_not_allowed”
Section titled “”trusted_proxy_user_not_allowed””The user is authenticated but isn’t in your allowUsers list. You’ll need to add them or clear the allowlist.
WebSocket Still Failing
Section titled “WebSocket Still Failing”If WebSockets aren’t working, make sure your proxy:
- Supports WebSocket upgrades (
Upgrade: websocket,Connection: upgrade). - Passes identity headers on the upgrade request.
- Doesn’t use a separate auth path for WebSocket connections.
Migration from Token Auth
Section titled “Migration from Token Auth”Moving from tokens to a trusted proxy? Follow these steps:
- Set up your proxy to authenticate users and pass headers.
- Test the proxy setup on its own using
curlwith headers. - Update your OpenClaw config to use trusted-proxy auth.
- Restart the Gateway.
- Test WebSocket connections from the Control UI.
- Run
openclaw security auditand check the results.
Related
Section titled “Related”- Security — full security guide
- Configuration — config reference
- Remote Access — other remote access patterns
- Tailscale — simpler alternative for tailnet-only access
Next Steps
Section titled “Next Steps”Need help getting your proxy configured? Check out our AI Setup Assistant for real-time guidance.
OpenClaw Expert
Still stuck?
If this page didn't answer your case, ask OpenClaw Expert for step-by-step guidance.