Simple, secure OAuth2 authentication for Kubernetes applications using the sidecar pattern.
Each application gets its own oauth2-proxy container that handles authentication transparentlyβno complex configuration needed.
- π Secure by Default - OAuth2/OIDC authentication with industry best practices
- π― Sidecar Pattern - Isolated authentication per application
- π Zero Application Changes - Drop-in authentication for any HTTP service
- π Single Sign-On - Share sessions across all
*.example.comapps - π¨ Customizable UI - Branded sign-in pages with Tailwind CSS
- π Observable - Prometheus metrics, health checks, audit logs
- π Multi-Provider - GitHub, Google, Azure AD, Generic OIDC
- π‘οΈ Security Hardened - Non-root containers, read-only filesystems, minimal privileges
π Full documentation: https://ianlintner.github.io/authproxy/
| Topic | Description |
|---|---|
| Quick Start | Get running in 5 minutes |
| Architecture | How it works with diagrams |
| Installation | Detailed setup guide |
| Adding Apps | Protect your applications |
| OAuth Providers | GitHub, Google, Azure AD |
| Configuration | All config options |
| Troubleshooting | Common issues & solutions |
- Kubernetes 1.20+ with
kubectlaccess - Istio 1.14+ service mesh installed
- Helm 3 installed
- Domain with DNS/TLS configured
- OAuth app registered (e.g., GitHub OAuth App)
GitHub
- Go to GitHub Settings β Developer settings β OAuth Apps
- Click New OAuth App
- Set Homepage URL:
https://example.com - Set Authorization callback URL:
https://auth.example.com/oauth2/callback - Save Client ID and generate a Client Secret
- Go to Google Cloud Console
- Create project β APIs & Services β Credentials
- Create OAuth 2.0 Client ID (Web application)
- Add Authorized redirect URI:
https://auth.example.com/oauth2/callback - Save Client ID and Client Secret
# Clone the repository
git clone https://github.com/ianlintner/authproxy.git
cd authproxy
# Install the helm chart
helm install oauth2-sidecar ./helm/oauth2-sidecar \
--set domain=example.com \
--set cookieDomain=.example.com \
--set oauth.provider=github \
--set oauth.clientID=Ov23li1234567890abcd \
--set oauth.clientSecret=1234567890abcdef1234567890abcdef12345678 \
--set istio.gateway.existingGateway=your-gateway \
--namespace defaultOr create a values file
# values.yaml
domain: example.com
cookieDomain: .example.com
oauth:
provider: github
clientID: Ov23li1234567890abcd
clientSecret: 1234567890abcdef1234567890abcdef12345678
istio:
gateway:
existingGateway: your-gatewayhelm install oauth2-sidecar ./helm/oauth2-sidecar \
-f values.yaml \
--namespace default# Deploy the example app
kubectl apply -k k8s/apps/example-app/
# Check deployment
kubectl get pods -l app=example-app# Visit your app (will redirect to GitHub/Google login)
open https://example-app.example.comYou should see:
- Sign-in page with your OAuth provider button
- OAuth consent screen (first time only)
- Your application - authenticated! π
βββββββββββββββ
β Browser β
ββββββββ¬βββββββ
β HTTPS
βΌ
βββββββββββββββββββ
β Istio Gateway β
β (TLS Term) β
βββββββββ¬ββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββ
β Kubernetes Service β
β (port 4180) β
βββββββββ¬βββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββ
β Pod β
β ββββββββββββββββββββββββββββ β
β β OAuth2 Proxy Sidecar β β
β β :4180 β β
β βββββββββββ¬βββββββββββββββββ β
β β localhost β
β βΌ β
β ββββββββββββββββββββββββββββ β
β β Your Application β β
β β :8080 β β
β ββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββ
- Traffic arrives at Istio Gateway with TLS termination
- VirtualService routes to Service port 4180
- OAuth2 Proxy sidecar receives request:
- β No cookie? β Redirect to OAuth provider sign-in
- β
Valid cookie? β Proxy to app on
localhost:8080
- Application receives request with injected headers:
X-Auth-Request-User:john.doeX-Auth-Request-Email:john.doe@example.comX-Auth-Request-Access-Token:gho_xxxx...
| Benefit | Description |
|---|---|
| Simple | No complex Istio ext_authz or EnvoyFilter configuration |
| Isolated | Each app has its own OAuth configuration |
| Debuggable | Logs and metrics co-located with your app |
| Flexible | Different OAuth providers per application |
| Portable | Easy to migrate apps between clusters |
See Architecture Documentation for detailed diagrams.
Configure your OAuth provider in the Helm values:
=== "GitHub"
yaml oauth: provider: github clientID: Ov23li1234567890 clientSecret: your-secret github: org: "my-company" # Optional: restrict to org team: "engineering" # Optional: restrict to team
=== "Google"
yaml oauth: provider: google clientID: 1234567890-abc123.apps.googleusercontent.com clientSecret: your-secret google: hostedDomain: "example.com" # Optional: restrict to domain
=== "Azure AD"
yaml oauth: provider: azure clientID: your-app-id clientSecret: your-secret azure: tenant: your-tenant-id
See OAuth Provider Documentation for detailed setup guides.
Customize the sign-in page with your branding:
customTemplates:
enabled: true
brandName: "My Company SSO"
logo: "<base64-encoded-logo>"# Session settings
session:
cookieExpire: 168h # 7 days
cookieRefresh: 1h # Refresh interval
# Email restrictions
email:
domains:
- "example.com"
- "partner.com"
# Extra arguments to oauth2-proxy
extraArgs:
- --skip-auth-regex=^/health
- --ssl-upstream-insecure-skip-verifyFull configuration reference: Configuration Options
./scripts/add-app.sh <app-name> <namespace> <app-port> <domain>
# Example:
./scripts/add-app.sh my-api default 8080 api.example.comAdd the oauth2-proxy sidecar to your deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
containers:
# OAuth2 Proxy sidecar
- name: oauth2-proxy
image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0
args:
- --config=/etc/oauth2-proxy/oauth2_proxy.cfg
env:
- name: OAUTH2_PROXY_UPSTREAMS
value: "http://127.0.0.1:8080"
ports:
- containerPort: 4180
volumeMounts:
- name: oauth2-proxy-config
mountPath: /etc/oauth2-proxy
- name: oauth2-proxy-templates
mountPath: /templates
# Your application
- name: app
image: my-app:latest
ports:
- containerPort: 8080
volumes:
- name: oauth2-proxy-config
configMap:
name: oauth2-proxy-sidecar-config
- name: oauth2-proxy-templates
configMap:
name: oauth2-proxy-templatesComplete guide: Adding Applications
Your application automatically receives user information via HTTP headers:
| Header | Description | Example |
|---|---|---|
X-Auth-Request-User |
Username | john.doe |
X-Auth-Request-Email |
Email address | john.doe@example.com |
X-Auth-Request-Preferred-Username |
Preferred username | johndoe |
X-Auth-Request-Access-Token |
OAuth access token | gho_xxxx... |
X-Forwarded-User |
User identifier | john.doe |
X-Forwarded-Email |
Email address | john.doe@example.com |
Authorization |
Bearer token | Bearer gho_xxxx... |
=== "Python / Flask" ```python from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def index():
user = request.headers.get('X-Auth-Request-User')
email = request.headers.get('X-Auth-Request-Email')
return f'Hello {user} ({email})!'
@app.route('/admin')
def admin():
email = request.headers.get('X-Auth-Request-Email')
if not email.endswith('@example.com'):
return 'Forbidden', 403
return 'Admin Panel'
```
=== "Node.js / Express" ```javascript const express = require('express'); const app = express();
app.get('/', (req, res) => {
const user = req.headers['x-auth-request-user'];
const email = req.headers['x-auth-request-email'];
res.send(`Hello ${user} (${email})!`);
});
app.get('/admin', (req, res) => {
const email = req.headers['x-auth-request-email'];
if (!email.endsWith('@example.com')) {
return res.status(403).send('Forbidden');
}
res.send('Admin Panel');
});
app.listen(8080);
```
=== "Go" ```go package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
user := r.Header.Get("X-Auth-Request-User")
email := r.Header.Get("X-Auth-Request-Email")
fmt.Fprintf(w, "Hello %s (%s)!", user, email)
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
```
OAuth2-proxy exposes health endpoints:
GET /ping- Liveness checkGET /ready- Readiness check
Metrics available at /metrics:
oauth2_proxy_requests_total
oauth2_proxy_authentication_attempts_total
oauth2_proxy_authentication_failures_total
oauth2_proxy_cookies_expired_total
View sidecar logs:
# View oauth2-proxy logs
kubectl logs -n default <pod-name> -c oauth2-proxy
# View application logs
kubectl logs -n default <pod-name> -c app
# Follow both
kubectl logs -n default <pod-name> --all-containers -fRedirect loop / Endless redirects
Cause: Callback URL mismatch
Solution: Ensure callback URL in OAuth provider matches:
https://auth.example.com/oauth2/callback
Check deployment env var:
kubectl get deployment -o yaml | grep REDIRECT_URLCookie not persisting / Sign in every time
Cause: Cookie domain mismatch
Solution: Verify cookie domain is .example.com:
kubectl get configmap oauth2-proxy-sidecar-config -o yaml | grep cookie_domains404 Not Found on protected paths
Cause: VirtualService routing to wrong port
Solution: Verify VirtualService routes to port 4180:
kubectl get virtualservice <app-name> -o yamlShould have:
destination:
host: <app-name>
port:
number: 4180 # oauth2-proxy portConnection refused to localhost:8080
Cause: Application not listening on localhost
Solution: Ensure app container listens on 0.0.0.0:8080 or 127.0.0.1:8080
See Troubleshooting Guide for more solutions.
authproxy/
βββ docs/ # MkDocs documentation
β βββ getting-started/ # Installation & quick start
β βββ architecture/ # Architecture with diagrams
β βββ guide/ # User guides
β βββ providers/ # OAuth provider setup
β βββ reference/ # API & config reference
βββ helm/
β βββ oauth2-sidecar/ # Helm chart
β βββ templates/ # Kubernetes templates
β βββ values.yaml # Default values
β βββ Chart.yaml # Chart metadata
βββ k8s/
β βββ base/ # Base resources
β β βββ istio/ # Gateway, VirtualService
β β βββ oauth2-proxy/ # ConfigMaps, templates
β βββ apps/
β βββ example-app/ # Complete working example
βββ scripts/
β βββ add-app.sh # Add auth to existing apps
β βββ setup.sh # Initial cluster setup
β βββ validate.sh # Validation checks
βββ examples/ # Example configurations
β βββ simple-app/ # Minimal example
βββ mkdocs.yml # Documentation config
βββ README.md # This file
Contributions are welcome! Please see Contributing Guide.
# Clone repository
git clone https://github.com/ianlintner/authproxy.git
cd authproxy
# Install documentation dependencies
pip install -r docs/requirements.txt
# Serve docs locally
mkdocs serve
# Run validation
./scripts/validate.sh