Protecting an app with ForwardAuth
This example walks through protecting a self-hosted app (we’ll use Grafana) with GateKeeper using Traefik’s ForwardAuth middleware.
What you’ll have at the end
Section titled “What you’ll have at the end”- Grafana at
https://grafana.example.com, accessible only to logged-in GateKeeper users. - GateKeeper at
https://auth.example.com, handling all authentication. - Traefik routing traffic and enforcing auth.
Full docker-compose.yml
Section titled “Full docker-compose.yml”services: traefik: image: traefik:v3 command: - --providers.docker=true - --providers.docker.exposedbydefault=false - --entrypoints.websecure.address=:443 - --certificatesresolvers.le.acme.tlschallenge=true - --certificatesresolvers.le.acme.email=you@example.com - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json ports: - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - letsencrypt:/letsencrypt
gatekeeper: image: ghcr.io/yourorg/gatekeeper:latest environment: BASE_URL: https://auth.example.com SECRET_KEY: your-32-char-secret-here ADMIN_EMAIL: admin@example.com ADMIN_PASSWORD: change-me SMTP_HOST: smtp.example.com SMTP_FROM: noreply@example.com SMTP_TLS: starttls volumes: - gk_data:/data labels: - traefik.enable=true - traefik.http.routers.gk.rule=Host(`auth.example.com`) - traefik.http.routers.gk.entrypoints=websecure - traefik.http.routers.gk.tls.certresolver=le - traefik.http.services.gk.loadbalancer.server.port=8080 - traefik.http.middlewares.gk-auth.forwardauth.address=http://gatekeeper:8080/auth/verify - traefik.http.middlewares.gk-auth.forwardauth.authResponseHeaders=X-Auth-User,X-Auth-Email
grafana: image: grafana/grafana:latest environment: GF_AUTH_PROXY_ENABLED: "true" GF_AUTH_PROXY_HEADER_NAME: X-Auth-Email GF_AUTH_PROXY_HEADER_PROPERTY: email GF_AUTH_PROXY_AUTO_SIGN_UP: "true" labels: - traefik.enable=true - traefik.http.routers.grafana.rule=Host(`grafana.example.com`) - traefik.http.routers.grafana.entrypoints=websecure - traefik.http.routers.grafana.tls.certresolver=le - traefik.http.routers.grafana.middlewares=gk-auth
volumes: gk_data: letsencrypt:How it works
Section titled “How it works”- A browser visits
grafana.example.com. - Traefik intercepts the request and calls
http://gatekeeper:8080/auth/verify. - If the user has a valid session, GateKeeper returns
200withX-Auth-Emailset. - Traefik forwards the request to Grafana with the
X-Auth-Emailheader. - Grafana uses proxy auth to log the user in automatically based on the header.
If the user has no session, GateKeeper returns 401 and Traefik redirects the browser to /login?redirect_uri=https://grafana.example.com/.
Reading identity headers in your own app
Section titled “Reading identity headers in your own app”If you build your own app, read the X-Auth-Email and X-Auth-User headers set by GateKeeper to identify the logged-in user:
# Flask example@app.route('/')def index(): user_email = request.headers.get('X-Auth-Email', 'anonymous') return f'Hello, {user_email}'// Go examplefunc handler(w http.ResponseWriter, r *http.Request) { email := r.Header.Get("X-Auth-Email") fmt.Fprintf(w, "Hello, %s", email)}