Skip to content

OAuth2 Proxy

Overview

OAuth2 Proxy provides centralized authentication for AKKO services that lack native OIDC support. It acts as an authentication gateway between Traefik and backend services, validating user sessions against Keycloak before allowing access. This eliminates the need to implement OAuth2/OIDC in every service.

Architecture

  Browser ──→ Traefik (:443)
                  │  forward-auth middleware
          OAuth2 Proxy (:4180)
                  │  validates session
              Keycloak
            (OIDC provider)
                  │  session valid → allow
          Backend Service
        (Dashboards, MLflow, LiteLLM, Cockpit)

Traefik's forward-auth middleware sends every incoming request to OAuth2 Proxy for validation. If the user has a valid session cookie, the request is forwarded to the backend. If not, the user is redirected to Keycloak's login page.

Ports

Port Purpose Exposed
4180 HTTP — authentication proxy endpoint Internal only (accessed by Traefik middleware)

Not Directly Accessible

Users never access OAuth2 Proxy directly. Traefik routes authentication requests to it transparently via the forward-auth middleware.

Protected Services

Service Why OAuth2 Proxy?
Dashboards Dashboards supports OAuth natively, but OAuth2 Proxy provides unified session management
MLflow No built-in authentication — fully open by default
LiteLLM API gateway with basic auth only — needs OIDC protection
Cockpit Static HTML/JS portal — no backend auth capability

Services with native Keycloak OIDC support (JupyterHub, Superset, Airflow, Keycloak itself) handle authentication directly and do not use OAuth2 Proxy.

Configuration

Keycloak OIDC Provider

OAuth2 Proxy is configured to use Keycloak as the OIDC identity provider:

provider: keycloak-oidc
oidc-issuer-url: https://identity.akko.local/realms/akko
client-id: akko-oauth2-proxy
client-secret: ${OAUTH2_PROXY_CLIENT_SECRET}
cookie-name: _akko_oauth2
cookie-secret: ${OAUTH2_PROXY_COOKIE_SECRET}   # 32-byte random base64
cookie-domain: .akko.local                      # shared across all subdomains
cookie-secure: true
cookie-samesite: lax

Cookie Domain Must Match

The cookie-domain must be set to the base domain shared by all services (.akko.local in k3d). If services use different domains, the session cookie will not be shared and users will face repeated login prompts.

Upstream and Redirect

upstream: static://200                    # return 200 for valid sessions
redirect-url: https://akko.local/oauth2/callback
email-domain: "*"                         # allow all email domains

The static://200 upstream means OAuth2 Proxy does not proxy traffic itself — it only validates the session and returns headers to Traefik.

Traefik Integration

The forward-auth middleware is defined as a Traefik CRD:

middleware.yaml
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: oauth2-proxy-forward-auth
spec:
  forwardAuth:
    address: http://akko-oauth2-proxy:4180/oauth2/auth
    trustForwardHeader: true
    authResponseHeaders:
      - X-Auth-Request-User
      - X-Auth-Request-Email
      - X-Auth-Request-Groups

Services that need protection add this annotation to their Ingress:

traefik.ingress.kubernetes.io/router.middlewares: >-
  akko-oauth2-proxy-forward-auth@kubernetescrd

Helm Chart

OAuth2 Proxy is deployed via the akko-oauth2-proxy custom sub-chart:

helm/akko/charts/akko-oauth2-proxy/
├── Chart.yaml
├── values.yaml
└── templates/
    ├── deployment.yaml
    ├── service.yaml
    ├── secret.yaml
    ├── middleware.yaml    # Traefik CRD
    └── ingress.yaml      # for /oauth2/callback

Key Values

values.yaml
akko-oauth2-proxy:
  image:
    repository: quay.io/oauth2-proxy/oauth2-proxy
    tag: "7.7.1"
  provider: keycloak-oidc
  cookie:
    domain: .akko.local
  ingress:
    enabled: true
    hostname: akko.local
    path: /oauth2

Health Check

GET http://akko-oauth2-proxy:4180/ping

Returns OK when the proxy is ready.

Troubleshooting

Common Issues

  • Infinite redirect loop: The most common cause is a mismatch between the redirect-url and the Keycloak client's valid redirect URIs. Verify in Keycloak admin (Clients > akko-oauth2-proxy > Valid Redirect URIs) that https://akko.local/oauth2/callback is listed. Also check the cookie domain.
  • 403 Forbidden after login: OAuth2 Proxy may reject the user if email-domain is too restrictive or the Keycloak token does not include the expected claims. Check OAuth2 Proxy logs with kubectl logs deploy/akko-oauth2-proxy for details.
  • Session lost between services: All services must share the same cookie-domain (.akko.local). If one service uses a different domain, the cookie is not sent and the user appears unauthenticated.