Forward Auth Proxy with Atom OIDC
Complete Docker Compose Examples
This guide shows how to use Atom's OIDC as the SSO provider with oauth2-proxy as a standalone forward authentication proxy (similar to Authentik's proxy).
Architecture
User Request → oauth2-proxy → Backend App
↓
Atom OIDC (SSO)
oauth2-proxy checks if user is authenticated:
- ✅ Authenticated: Proxies to backend with user headers
- ❌ Not authenticated: Redirects to Atom for login
Example 1: Grafana with Forward Auth
version: '3.8'
services:
# Atom Dashboard (SSO Provider)
atom:
image: your-atom-image:latest
ports:
- "3000:3000"
environment:
- OAUTH_ISSUER_URL=http://atom:3000
networks:
- apps
# Grafana (Backend Application)
grafana:
image: grafana/grafana:latest
environment:
# Configure Grafana to trust proxy headers
- GF_AUTH_PROXY_ENABLED=true
- GF_AUTH_PROXY_HEADER_NAME=X-Forwarded-User
- GF_AUTH_PROXY_HEADER_PROPERTY=username
- GF_AUTH_PROXY_AUTO_SIGN_UP=true
- GF_USERS_ALLOW_SIGN_UP=false
networks:
- apps
# oauth2-proxy (Forward Auth Proxy)
grafana-proxy:
image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0
command:
- --provider=oidc
- --oidc-issuer-url=http://atom:3000
- --client-id=grafana-client # Create in Atom
- --client-secret=your-secret-here
- --cookie-secret=random-32-character-string-here
- --redirect-url=http://localhost:8080/oauth2/callback
- --upstream=http://grafana:3000
- --email-domain=*
- --pass-user-headers=true
- --pass-access-token=true
- --set-xauthrequest=true
- --cookie-secure=false # Set true in production with HTTPS
ports:
- "8080:4180"
networks:
- apps
depends_on:
- atom
- grafana
networks:
apps:
driver: bridge
Access: http://localhost:8080 → oauth2-proxy → Grafana
Example 2: Multiple Apps with Traefik
Use Traefik as reverse proxy + oauth2-proxy for SSO:
version: '3.8'
services:
# Traefik Reverse Proxy
traefik:
image: traefik:v3.0
command:
- --api.insecure=true
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
ports:
- "80:80"
- "8081:8080" # Traefik dashboard
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- proxy
# Atom Dashboard (SSO Provider)
atom:
image: your-atom-image:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.atom.rule=Host(`atom.localhost`)"
- "traefik.http.services.atom.loadbalancer.server.port=3000"
environment:
- OAUTH_ISSUER_URL=http://atom.localhost
networks:
- proxy
# oauth2-proxy for SSO
oauth2-proxy:
image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0
command:
- --provider=oidc
- --oidc-issuer-url=http://atom.localhost
- --client-id=proxy-client
- --client-secret=your-secret
- --cookie-secret=random-32-chars-xxxxxxxxxxxxxxxx
- --redirect-url=http://auth.localhost/oauth2/callback
- --email-domain=*
- --upstream=static://202
- --cookie-secure=false
labels:
- "traefik.enable=true"
- "traefik.http.routers.oauth2-proxy.rule=Host(`auth.localhost`)"
- "traefik.http.services.oauth2-proxy.loadbalancer.server.port=4180"
networks:
- proxy
# Grafana (Protected App)
grafana:
image: grafana/grafana:latest
environment:
- GF_AUTH_PROXY_ENABLED=true
- GF_AUTH_PROXY_HEADER_NAME=X-Forwarded-User
- GF_AUTH_PROXY_AUTO_SIGN_UP=true
labels:
- "traefik.enable=true"
- "traefik.http.routers.grafana.rule=Host(`grafana.localhost`)"
- "traefik.http.routers.grafana.middlewares=oauth2-auth"
- "traefik.http.middlewares.oauth2-auth.forwardauth.address=http://oauth2-proxy:4180"
- "traefik.http.middlewares.oauth2-auth.forwardauth.authResponseHeaders=X-Auth-Request-User,X-Auth-Request-Email"
- "traefik.http.services.grafana.loadbalancer.server.port=3000"
networks:
- proxy
# Portainer (Another Protected App)
portainer:
image: portainer/portainer-ce:latest
command: --http-enabled
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer_data:/data
labels:
- "traefik.enable=true"
- "traefik.http.routers.portainer.rule=Host(`portainer.localhost`)"
- "traefik.http.routers.portainer.middlewares=oauth2-auth" # Same auth!
- "traefik.http.services.portainer.loadbalancer.server.port=9000"
networks:
- proxy
volumes:
portainer_data:
networks:
proxy:
driver: bridge
Access:
- Atom:
http://atom.localhost - Grafana:
http://grafana.localhost(SSO via Atom) - Portainer:
http://portainer.localhost(SSO via Atom)
Example 3: Per-App Proxy (Authentik Style)
Each app gets its own dedicated proxy container:
version: '3.8'
services:
# Atom Dashboard
atom:
image: your-atom-image:latest
ports:
- "3000:3000"
environment:
- OAUTH_ISSUER_URL=http://atom:3000
networks:
- media_stack
# Sonarr
sonarr:
image: linuxserver/sonarr:latest
environment:
- PUID=1000
- PGID=1000
volumes:
- ./sonarr:/config
networks:
media_stack:
ipv4_address: 172.30.0.10
# Sonarr Auth Proxy
sonarr-proxy:
image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0
environment:
- OAUTH2_PROXY_PROVIDER=oidc
- OAUTH2_PROXY_OIDC_ISSUER_URL=http://atom:3000
- OAUTH2_PROXY_CLIENT_ID=sonarr-client
- OAUTH2_PROXY_CLIENT_SECRET=sonarr-secret
- OAUTH2_PROXY_COOKIE_SECRET=random32chars_xxxxxxxxxxxxxxxx
- OAUTH2_PROXY_REDIRECT_URL=http://sonarr.yourdomain.com/oauth2/callback
- OAUTH2_PROXY_UPSTREAMS=http://172.30.0.10:8989
- OAUTH2_PROXY_EMAIL_DOMAINS=*
- OAUTH2_PROXY_PASS_USER_HEADERS=true
- OAUTH2_PROXY_COOKIE_SECURE=false
ports:
- "8989:4180"
networks:
media_stack:
ipv4_address: 172.30.0.11
# Radarr
radarr:
image: linuxserver/radarr:latest
environment:
- PUID=1000
- PGID=1000
volumes:
- ./radarr:/config
networks:
media_stack:
ipv4_address: 172.30.0.12
# Radarr Auth Proxy
radarr-proxy:
image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0
environment:
- OAUTH2_PROXY_PROVIDER=oidc
- OAUTH2_PROXY_OIDC_ISSUER_URL=http://atom:3000
- OAUTH2_PROXY_CLIENT_ID=radarr-client
- OAUTH2_PROXY_CLIENT_SECRET=radarr-secret
- OAUTH2_PROXY_COOKIE_SECRET=random32chars_yyyyyyyyyyyyyyyy
- OAUTH2_PROXY_REDIRECT_URL=http://radarr.yourdomain.com/oauth2/callback
- OAUTH2_PROXY_UPSTREAMS=http://172.30.0.12:7878
- OAUTH2_PROXY_EMAIL_DOMAINS=*
- OAUTH2_PROXY_PASS_USER_HEADERS=true
- OAUTH2_PROXY_COOKIE_SECURE=false
ports:
- "7878:4180"
networks:
media_stack:
ipv4_address: 172.30.0.13
networks:
media_stack:
driver: bridge
ipam:
config:
- subnet: 172.30.0.0/24
Setup Steps
1. Create OAuth2 Client in Atom
Via Atom UI (Settings → SSO Provider):
- Click "Add Application"
- Name:
Grafana(or app name) - Redirect URIs:
http://localhost:8080/oauth2/callback - Allowed Scopes:
openid,profile,email - Save and copy Client ID and Client Secret
Or via API:
curl -X POST http://localhost:3000/api/oauth/clients \
-H "Content-Type: application/json" \
-H "Cookie: your-session-cookie" \
-d '{
"name": "Grafana",
"redirect_uris": ["http://localhost:8080/oauth2/callback"],
"allowed_scopes": ["openid", "profile", "email"],
"grant_types": ["authorization_code", "refresh_token"]
}'
2. Generate Cookie Secret
3. Configure Backend App
Most apps support proxy authentication via headers:
Grafana:
[auth.proxy]
enabled = true
header_name = X-Forwarded-User
auto_sign_up = true
Nextcloud (config.php):
'trusted_proxies' => ['172.30.0.0/24'],
'forwarded_for_headers' => ['HTTP_X_FORWARDED_FOR'],
Generic App:
Configure to trust X-Forwarded-User or X-Remote-User header
4. Start Services
docker-compose up -d
5. Test
- Visit
http://localhost:8080 - Redirect to Atom login
- Login with Atom credentials
- Redirect back to app (auto-logged in)
Environment Variables Reference
oauth2-proxy Configuration
Injected Headers
oauth2-proxy injects these headers to the backend:
X-Forwarded-User: UsernameX-Forwarded-Email: EmailX-Auth-Request-User: Username (alternative)X-Auth-Request-Email: Email (alternative)Authorization: Bearer token
Production Considerations
HTTPS/TLS
oauth2-proxy:
environment:
- OAUTH2_PROXY_COOKIE_SECURE=true
- OAUTH2_PROXY_REDIRECT_URL=https://app.yourdomain.com/oauth2/callback
Session Duration
oauth2-proxy:
environment:
- OAUTH2_PROXY_COOKIE_EXPIRE=12h
- OAUTH2_PROXY_COOKIE_REFRESH=1h
Restrict Users
oauth2-proxy:
environment:
- OAUTH2_PROXY_EMAIL_DOMAINS=yourdomain.com
# or
- OAUTH2_PROXY_AUTHENTICATED_EMAILS_FILE=/emails.txt
Testing the Setup
1. Check Atom OIDC Discovery
curl http://localhost:3000/.well-known/openid-configuration | jq
2. Check oauth2-proxy Health
curl http://localhost:4180/ping
# Should return: OK
3. Test Auth Flow
# Visit protected app
curl -I http://localhost:8080/
# Should redirect to Atom for login
# Location: http://atom:3000/api/oauth/authorize?...
Summary
✅ Atom provides: OIDC/OAuth2 SSO
✅ oauth2-proxy provides: Forward authentication
✅ Works with: Any app that trusts proxy headers
✅ Deployment: One proxy per app (Authentik-style)
This is the production-ready, industry-standard approach for SSO!