Proxy auth — nginx + oauth2-proxy
Run oauth2-proxy alongside nginx for a self-hosted OIDC login in front of chmonitor, using nginx's auth_request to gate every request.
oauth2-proxy handles the OIDC login flow (Google, GitHub, Okta, Dex, Keycloak, any OIDC provider) and, once a session cookie is valid, emits identity headers on an internal auth-check endpoint. nginx uses auth_request to call that endpoint on every request; if it returns 200, nginx copies the identity headers onto the real request to chmonitor along with a shared secret. chmonitor's trusted auth provider reads those headers into a full user profile (name, email, avatar, groups) and gates access on the shared secret.
When to pick this path
Use this when you're already running nginx (or nginx-ingress) and want a self-hosted OIDC login without Cloudflare, and you want more than a bare identity — group-based access gating, display name, and avatar in the chmonitor UI.
Prerequisites
- nginx (or nginx-ingress) able to run
auth_request(built in to nginx'shttp_auth_request_module, enabled by default on most distro packages and the official nginx image). - An OIDC provider: Google Workspace, GitHub OAuth app, Okta, Keycloak, Dex, Authentik, or similar — you need a client ID + client secret from it.
- Docker or a way to run the
oauth2-proxybinary as a long-running process.
Setup
Generate a cookie secret
python3 -c 'import os,base64; print(base64.urlsafe_b64encode(os.urandom(32)).decode())'Save the output — you'll pass it as --cookie-secret.
Run oauth2-proxy
Example with Google as the OIDC provider (swap --provider and its flags for your IdP):
docker run -d \
--name oauth2-proxy \
-p 4180:4180 \
quay.io/oauth2-proxy/oauth2-proxy:latest \
--provider=google \
--client-id=YOUR_CLIENT_ID \
--client-secret=YOUR_CLIENT_SECRET \
--cookie-secret=<output-from-step-1> \
--email-domain=yourcompany.com \
--http-address=0.0.0.0:4180 \
--upstream=http://chmonitor:8080 \
--set-xauthrequest \
--pass-access-token=false \
--cookie-secure=true \
--redirect-url=https://chmonitor.yourcompany.com/oauth2/callbackKey flags:
--set-xauthrequest— emitsX-Auth-Request-User,X-Auth-Request-Email,X-Auth-Request-Preferred-Username, andX-Auth-Request-Groupsresponse headers on the internal/oauth2/authcheck. This is exactly what nginx'sauth_requestreads.--upstream=http://chmonitor:8080— oauth2-proxy can itself reverse-proxy to chmonitor, but in this setup nginx is the front door and only calls oauth2-proxy for the auth check (/oauth2/auth,/oauth2/sign_in,/oauth2/callback) — the--upstreamvalue mainly matters if you ever hit oauth2-proxy directly.--email-domain=yourcompany.com— restrict who can complete login; use*to allow any authenticated Google account (not recommended for anything but testing).- If your IdP supports groups (Okta, Keycloak, Dex, Authentik), also request the
groupsscope, e.g.--scope="openid email profile groups", soX-Auth-Request-Groupsis populated forCHM_TRUSTED_ALLOWED_GROUPSgating.
Configure nginx
server {
listen 443 ssl;
server_name chmonitor.yourcompany.com;
# oauth2-proxy's own endpoints (login page, callback)
location /oauth2/ {
proxy_pass http://oauth2-proxy:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
}
# Internal auth-check endpoint nginx calls on every request
location = /oauth2/auth {
internal;
proxy_pass http://oauth2-proxy:4180;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
location / {
auth_request /oauth2/auth;
error_page 401 = /oauth2/sign_in?rd=$scheme://$host$request_uri;
# Pull identity headers off the auth_request response
auth_request_set $user $upstream_http_x_auth_request_user;
auth_request_set $email $upstream_http_x_auth_request_email;
auth_request_set $name $upstream_http_x_auth_request_preferred_username;
auth_request_set $groups $upstream_http_x_auth_request_groups;
proxy_set_header X-Forwarded-User $user;
proxy_set_header X-Forwarded-Email $email;
proxy_set_header X-Forwarded-Preferred-Username $name;
proxy_set_header X-Forwarded-Groups $groups;
# Shared secret so chmonitor trusts these headers — never hardcode in
# source control; inject via envsubst / a secrets manager at deploy time.
proxy_set_header X-Chm-Proxy-Secret "your-shared-secret-here";
# Required for the AI agent chat's streaming (SSE-style) responses:
# buffering would hold the whole response until it completes.
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off;
proxy_read_timeout 3600s;
proxy_pass http://chmonitor:8080;
}
}Don't hardcode the secret in source control
Load X-Chm-Proxy-Secret's value at deploy time with envsubst, a secrets manager (Vault Agent, SOPS), or a templating step — never commit the literal secret in an nginx config file.
Configure chmonitor
Prop
Type
CHM_AUTH_PROVIDER=trusted
CHM_TRUSTED_AUTH_SECRET=your-shared-secret-here # must match nginx's X-Chm-Proxy-Secret value
# defaults already line up with X-Forwarded-User / X-Forwarded-Email / etc.
# CHM_TRUSTED_USER_HEADER=X-Forwarded-User
# CHM_TRUSTED_EMAIL_HEADER=X-Forwarded-Email
# CHM_TRUSTED_NAME_HEADER=X-Forwarded-Preferred-Username
# CHM_TRUSTED_GROUPS_HEADER=X-Forwarded-Groups
# Optional: restrict access to specific oauth2-proxy/IdP groups
# CHM_TRUSTED_ALLOWED_GROUPS=sre,ops,adminSet the secret out-of-band, not in a plaintext .env committed to source control:
wrangler secret put CHM_TRUSTED_AUTH_SECRET
# or, for Docker/K8s:
kubectl create secret generic chm-trusted-secret --from-literal=value=<secret>Verify
# Hit chmonitor directly, bypassing nginx — must 401 (no secret header)
curl -i http://chmonitor:8080/api/v1/auth/me
# Through nginx without a session — redirected to oauth2-proxy's login
curl -i https://chmonitor.yourcompany.com/
# Through nginx with a valid session cookie — returns the authenticated principal
curl -b "_oauth2_proxy=<cookie-value>" https://chmonitor.yourcompany.com/api/v1/auth/me | jq .Troubleshooting
Related
Proxy auth overview
Compare all three proxy patterns.
Cloudflare Access + Tunnel
Zero Trust, signed JWT, no shared secret.
Traefik ForwardAuth + OIDC
Traefik middleware forwarding an OIDC session.
Trusted forwarded headers reference
Full env var reference for the trusted provider.
Authentication overview
Compare all chmonitor auth providers.