OAuth2 Proxy Cheat Sheet
Overview
OAuth2 Proxy is a reverse proxy and static file server that provides authentication using OAuth 2.0 identity providers (Google, GitHub, Azure, Keycloak, etc.) to validate accounts by email, domain, or group. It sits in front of your application and handles the authentication flow, passing verified user information to the upstream service via headers.
OAuth2 Proxy is ideal for adding authentication to applications that lack built-in auth, protecting internal tools, and standardizing authentication across multiple services. It supports cookie-based sessions, JWT tokens, Redis session storage, and can be configured with Nginx, Traefik, or any reverse proxy that supports auth subrequests.
Installation
# Binary download
curl -L https://github.com/oauth2-proxy/oauth2-proxy/releases/download/v7.6.0/oauth2-proxy-v7.6.0.linux-amd64.tar.gz | tar xz
sudo mv oauth2-proxy-v7.6.0.linux-amd64/oauth2-proxy /usr/local/bin/
# Docker
docker pull quay.io/oauth2-proxy/oauth2-proxy
# Homebrew
brew install oauth2-proxy
# Go install
go install github.com/oauth2-proxy/oauth2-proxy/v7@latest
# Verify
oauth2-proxy --version
Basic Usage
# Start with Google provider
oauth2-proxy \
--provider=google \
--client-id=YOUR_CLIENT_ID \
--client-secret=YOUR_CLIENT_SECRET \
--cookie-secret=$(python3 -c "import os,base64; print(base64.urlsafe_b64encode(os.urandom(32)).decode())") \
--email-domain=example.com \
--upstream=http://localhost:8080 \
--http-address=0.0.0.0:4180
# Start with GitHub provider
oauth2-proxy \
--provider=github \
--client-id=YOUR_CLIENT_ID \
--client-secret=YOUR_CLIENT_SECRET \
--cookie-secret=RANDOM_SECRET \
--github-org=my-org \
--upstream=http://localhost:8080 \
--http-address=0.0.0.0:4180
Provider Configuration
oauth2-proxy \
--provider=google \
--client-id=$GOOGLE_CLIENT_ID \
--client-secret=$GOOGLE_CLIENT_SECRET \
--email-domain=example.com \
--cookie-secret=$COOKIE_SECRET
GitHub
oauth2-proxy \
--provider=github \
--client-id=$GITHUB_CLIENT_ID \
--client-secret=$GITHUB_CLIENT_SECRET \
--github-org=my-organization \
--github-team=developers,devops \
--cookie-secret=$COOKIE_SECRET
Azure AD / Entra ID
oauth2-proxy \
--provider=azure \
--client-id=$AZURE_CLIENT_ID \
--client-secret=$AZURE_CLIENT_SECRET \
--oidc-issuer-url=https://login.microsoftonline.com/TENANT_ID/v2.0 \
--email-domain=example.com \
--cookie-secret=$COOKIE_SECRET
Keycloak / Generic OIDC
oauth2-proxy \
--provider=oidc \
--client-id=$KEYCLOAK_CLIENT_ID \
--client-secret=$KEYCLOAK_CLIENT_SECRET \
--oidc-issuer-url=https://keycloak.example.com/realms/myrealm \
--email-domain=* \
--cookie-secret=$COOKIE_SECRET \
--scope="openid email profile groups"
Configuration File
# oauth2-proxy.cfg
provider = "oidc"
client_id = "my-client-id"
client_secret = "my-client-secret"
oidc_issuer_url = "https://auth.example.com"
cookie_secret = "base64-encoded-32-byte-secret"
cookie_secure = true
cookie_domains = [".example.com"]
cookie_samesite = "lax"
email_domains = ["example.com"]
upstreams = ["http://localhost:8080"]
http_address = "0.0.0.0:4180"
redirect_url = "https://app.example.com/oauth2/callback"
pass_access_token = true
pass_authorization_header = true
set_authorization_header = true
set_xauthrequest = true
skip_provider_button = true
# Session storage
session_store_type = "redis"
redis_connection_url = "redis://redis:6379"
Common Flags
| Flag | Description |
|---|---|
--provider | OAuth provider (google, github, azure, oidc, etc.) |
--client-id | OAuth client ID |
--client-secret | OAuth client secret |
--cookie-secret | Secret for cookie encryption (32 bytes, base64) |
--email-domain | Restrict to email domain (* for any) |
--upstream | Upstream application URL |
--http-address | Listen address |
--redirect-url | OAuth callback URL |
--pass-access-token | Pass OAuth access token to upstream |
--set-xauthrequest | Set X-Auth-Request headers |
--set-authorization-header | Set Authorization Bearer header |
--skip-provider-button | Skip the login button page |
--whitelist-domain | Allowed redirect domains |
--authenticated-emails-file | File with allowed emails |
--cookie-expire | Cookie expiration time |
--cookie-refresh | Cookie refresh interval |
--skip-auth-regex | Paths to skip authentication |
Nginx Integration
server {
listen 443 ssl;
server_name app.example.com;
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-Auth-Request-Redirect $request_uri;
}
location = /oauth2/auth {
proxy_pass http://oauth2-proxy:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Content-Length "";
proxy_pass_request_body off;
}
location / {
auth_request /oauth2/auth;
error_page 401 = /oauth2/sign_in;
auth_request_set $user $upstream_http_x_auth_request_user;
auth_request_set $email $upstream_http_x_auth_request_email;
auth_request_set $auth $upstream_http_authorization;
proxy_set_header X-User $user;
proxy_set_header X-Email $email;
proxy_set_header Authorization $auth;
proxy_pass http://backend:8080;
}
}
Traefik Integration
# docker-compose.yml
services:
oauth2-proxy:
image: quay.io/oauth2-proxy/oauth2-proxy
command:
- --provider=oidc
- --oidc-issuer-url=https://auth.example.com
- --client-id=${CLIENT_ID}
- --client-secret=${CLIENT_SECRET}
- --cookie-secret=${COOKIE_SECRET}
- --email-domain=*
- --upstream=static://202
- --reverse-proxy=true
- --set-xauthrequest=true
- --http-address=0.0.0.0:4180
labels:
- "traefik.http.middlewares.oauth.forwardAuth.address=http://oauth2-proxy:4180/oauth2/auth"
- "traefik.http.middlewares.oauth.forwardAuth.trustForwardHeader=true"
- "traefik.http.middlewares.oauth.forwardAuth.authResponseHeaders=X-Auth-Request-User,X-Auth-Request-Email,Authorization"
my-app:
image: my-app:latest
labels:
- "traefik.http.routers.myapp.middlewares=oauth@docker"
Advanced Usage
Skip Auth for Specific Paths
oauth2-proxy \
--skip-auth-regex="^/health$" \
--skip-auth-regex="^/api/public/.*" \
--skip-auth-regex="^/static/.*"
Allowed Email List
# Create file with allowed emails
cat > /etc/oauth2-proxy/emails.txt <<EOF
admin@example.com
developer@example.com
EOF
oauth2-proxy \
--authenticated-emails-file=/etc/oauth2-proxy/emails.txt
Redis Session Storage
oauth2-proxy \
--session-store-type=redis \
--redis-connection-url="redis://redis:6379" \
--redis-password="redis-password" \
--cookie-refresh=1h
Multiple Upstreams
oauth2-proxy \
--upstream="http://app1:8080/app1/" \
--upstream="http://app2:8080/app2/" \
--upstream="file:///var/www/static/#/static/"
Configuration
# Generate cookie secret
python3 -c "import os,base64; print(base64.urlsafe_b64encode(os.urandom(32)).decode())"
# Or with openssl
openssl rand -base64 32
# Environment variables (prefix with OAUTH2_PROXY_)
export OAUTH2_PROXY_PROVIDER=oidc
export OAUTH2_PROXY_CLIENT_ID=my-client-id
export OAUTH2_PROXY_CLIENT_SECRET=my-client-secret
export OAUTH2_PROXY_COOKIE_SECRET=base64-secret
export OAUTH2_PROXY_OIDC_ISSUER_URL=https://auth.example.com
export OAUTH2_PROXY_EMAIL_DOMAINS=example.com
Troubleshooting
| Issue | Solution |
|---|---|
| Redirect loop | Check redirect-url matches callback URL; verify cookie domain |
| 403 after login | Check email-domain, github-org, or allowed emails config |
| Cookie too large | Switch to Redis session storage; cookies have 4KB browser limit |
| CORS issues | Set --whitelist-domain and configure upstream CORS headers |
| Provider discovery fails | Verify --oidc-issuer-url is accessible and returns OIDC config |
| Session expiring too fast | Increase --cookie-expire; enable --cookie-refresh |
| Headers not passed to upstream | Enable --set-xauthrequest and --pass-access-token |
| Multiple domain SSO fails | Set --cookie-domains=.example.com for parent domain |