OAuth2-Proxy

oauth2-proxy ist ein vorgeschalteter Reverse Proxy, der Authentifizierung an einen OAuth2- oder OpenID-Connect-Provider (z.B. Keycloak, Google, GitHub) delegiert. Ist ein Request nicht authentifiziert, lenkt der Proxy den Benutzer zum Login-Flow der konfigurierten IdP-Seite um; bei Erfolg setzt er ein Session-Cookie und reicht den Request (mit zusätzlichen Headern wie X-Forwarded-User) an das Backend weiter. Damit lässt sich praktisch jede Webapp ohne eigene Authentifizierungslogik hinter Single-Sign-On (SSO) stellen.

Die Redirect-URL für den OAuth-Flow lautet standardmässig https://<host>/oauth2/callback. Der Proxy selbst lauscht auf Port 4180/tcp hinter einem Reverse-Proxy (Apache/Nginx/HAProxy) oder direkt auf 443/tcp.

Begriffe

Access Token

Kurzlebiges Token, das einen authentifizierten Zugriff auf eine Ressource erlaubt (typisch 5 bis 60 Minuten). In OAuth 2.0 ein intransparenter String, bei OIDC-Providern häufig ein JWT.

Authorization Code Flow

Standardisierter OAuth-Ablauf für Web-Anwendungen: der Browser wird zum IdP umgeleitet, der User loggt sich ein, der IdP antwortet mit einem kurzlebigen Code, den der Proxy serverseitig gegen Tokens tauscht. Voraussetzung für das clientseitige Geheimnis (client_secret), das oauth2-proxy verwendet.

Client

Eine beim IdP registrierte Applikation, hier oauth2-proxy selbst. Identifiziert sich mit client_id und client_secret. Bei Keycloak entspricht dem ein Eintrag unter Clients mit Access-Type confidential.

ID Token

OIDC-spezifisches JWT mit Identitätsdaten des Benutzers (sub, email, preferred_username, Gruppen, …). Wird zusammen mit dem Access Token ausgestellt und ist der Grund, weshalb OIDC im Unterschied zu reinem OAuth 2.0 für Authentifizierung genutzt werden kann.

OAuth 2.0

Protokoll für delegierte Autorisierung (RFC 6749). Ursprünglich nicht für Authentifizierung gedacht - dafür kam OIDC hinzu.

OIDC (OpenID Connect)

Erweiterung auf OAuth 2.0, die Authentifizierung und Benutzerprofil standardisiert (ID Token, /userinfo-Endpunkt, Discovery). Heute der De-facto-Standard für SSO zwischen Web-Anwendungen.

PKCE

Proof Key for Code Exchange (RFC 7636). Schützt den Authorization Code Flow gegen Code-Interception-Angriffe durch einen pro Request zufällig erzeugten code_verifier. Für oauth2-proxy seit 7.x per --code-challenge-method=S256 empfohlen.

Refresh Token

Langlebiges Token zum Erneuern eines abgelaufenen Access Tokens ohne erneuten User-Login. Wird serverseitig in der oauth2-proxy-Session abgelegt.

Session

oauth2-proxy hält den Login-Zustand in einem verschlüsselten Cookie (cookie session store) oder in Redis. Der Default ist das Cookie; Redis wird notwendig, sobald Token-Grössen das Browser-Cookie-Limit (typisch 4 KB) sprengen oder mehrere Proxy-Instanzen horizontal skaliert werden.

Installation

Oauth2-proxy liegt als statisches Binary auf GitHub. Aktuelle Version prüfen und anpassen:

VER=7.7.1
cd /tmp
wget "https://github.com/oauth2-proxy/oauth2-proxy/releases/download/v${VER}/oauth2-proxy-v${VER}.linux-amd64.tar.gz"
tar --extract --gzip --verbose --file "oauth2-proxy-v${VER}.linux-amd64.tar.gz"
mv "oauth2-proxy-v${VER}.linux-amd64" /opt/
ln --symbolic --force "/opt/oauth2-proxy-v${VER}.linux-amd64" /opt/oauth2-proxy

Konfigurationsdatei /etc/oauth2-proxy.cfg passend zum genutzten IdP-Provider anlegen (siehe Abschnitt Integration mit Keycloak). Start:

/opt/oauth2-proxy/oauth2-proxy --config=/etc/oauth2-proxy.cfg

Bemerkung

Die Konfigurationsdatei folgt einem abgewandelten Kommandozeilen-Format: alle Vorkommen von - im Argumentnamen werden durch _ ersetzt, und mehrfach angegebene CLI-Argumente werden in der Datei als Liste mit Pluralform notiert (z.B. CLI --email-domain entspricht dem Config-Key email_domains).

Die vollständige Liste der Kommandozeilen-Argumente zeigt:

/opt/oauth2-proxy/oauth2-proxy --help

systemd-Service

/etc/systemd/system/oauth2-proxy.service
[Unit]
Description=oauth2-proxy
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=oauth2-proxy
Group=oauth2-proxy
ExecStart=/opt/oauth2-proxy/oauth2-proxy --config=/etc/oauth2-proxy.cfg
Restart=on-failure
RestartSec=5
# hardening
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/oauth2-proxy

[Install]
WantedBy=multi-user.target
useradd --system --home-dir /var/lib/oauth2-proxy --shell /sbin/nologin oauth2-proxy
mkdir --parents /var/lib/oauth2-proxy
chown oauth2-proxy:oauth2-proxy /var/lib/oauth2-proxy
chmod 600 /etc/oauth2-proxy.cfg
chown oauth2-proxy:oauth2-proxy /etc/oauth2-proxy.cfg
systemctl daemon-reload
systemctl enable --now oauth2-proxy

Unterstützte Provider

Der Proxy kennt eine Reihe vordefinierter Provider-Module (Auswahl):

  • Azure AD / Microsoft Entra ID

  • Bitbucket

  • DigitalOcean

  • Facebook

  • GitHub

  • GitLab

  • Google

  • Keycloak (keycloak und keycloak-oidc)

  • LinkedIn

  • Nextcloud

  • Okta

  • generischer OIDC-Provider (oidc)

Die gepflegteste Variante für OIDC-konforme IdPs ist keycloak-oidc bzw. oidc, da sie automatisch Discovery (/.well-known/openid-configuration) verwendet und den /userinfo-Endpunkt korrekt behandelt.

Integration mit Keycloak

Keycloak-Seite: neuer Client „oauth2-proxy“ vom Typ openid-connect anlegen.

  • Clientsoauth2-proxySettings:

    • Client ID: oauth2-proxy

    • Client Protocol: openid-connect

    • Access Type: confidential

    • Valid Redirect URIs: https://internal.example.com/oauth2/callback

  • Clientsoauth2-proxyMappersCreate:

    • Name: OAuth Group Membership

    • Mapper Type: Group Membership

    • Token Claim Name: groups

oauth2-proxy-Seite: Konfiguration gegen Keycloak in der Datei /etc/oauth2-proxy.cfg:

/etc/oauth2-proxy.cfg
provider="keycloak-oidc"
client_id="<client-id>"
client_secret="<client-secret>"
oidc_issuer_url="https://keycloak.example.com/realms/<realm>"
code_challenge_method="S256"
allowed_groups=["/admin", "/consultants"]

# any base64-encoded secret (32 bytes before base64)
cookie_secret="<base64-encoded-32-byte-secret>"
email_domains=["*"]

# listen address: HTTP behind a reverse proxy, or 443/tcp directly
http_address="203.0.113.76:4180"

# pass identity headers to upstreams
pass_access_token=true
set_xauthrequest=true

Das cookie_secret lässt sich z.B. so erzeugen:

python3 -c 'import os, base64; print(base64.urlsafe_b64encode(os.urandom(32)).decode())'

Konfigurations-Optionen im Überblick

Ein paar wiederkehrende Parameter, die in produktiven Setups gesetzt werden:

allowed_groups

Whitelist von Gruppen aus dem IdP. oauth2-proxy leitet ausschliesslich User durch, die in einer der Gruppen Mitglied sind.

cookie_secure

Setzt das Session-Cookie nur über HTTPS (Standard true). In produktiven Deployments nicht auf false setzen, auch nicht hinter einem Reverse-Proxy, der selbst TLS terminiert - oauth2-proxy kennt das X-Forwarded-Proto-Header, damit das Cookie auch in dieser Konstellation als Secure markiert wird.

email_domains

Whitelist der akzeptierten E-Mail-Domains. Mit "*" jede Domain; sinnvollerweise fachlich einengen (z.B. ["example.com"]), um die Angriffsfläche auf Konten im IdP zu begrenzen.

pass_access_token / pass_authorization_header

Gibt das OAuth-Access-Token bzw. den Authorization-Header an das Backend weiter. Benötigt, wenn das Backend selbst gegen den IdP validiert.

session_store_type

cookie (Default) oder redis. Redis ist ab Gruppen-Claims oder grösseren JWTs fast immer notwendig.

skip_auth_regex

Liste von URL-Regexes, die ohne Authentifizierung durchgereicht werden - praktisch für Health-Checks (^/healthz$) oder öffentliche statische Inhalte.

upstream

URL des Backends, an das oauth2-proxy nach erfolgreicher Authentifizierung weiterleitet. Mehrere upstream-Einträge erlauben pfadbasiertes Fan-out.

Identitäts-Header für das Backend

Mit set_xauthrequest=true setzt oauth2-proxy nach erfolgreicher Authentifizierung diese Header auf den Weg zum Backend:

  • X-Auth-Request-Access-Token (nur bei pass_access_token=true)

  • X-Auth-Request-Email

  • X-Auth-Request-Groups

  • X-Auth-Request-Preferred-Username

  • X-Auth-Request-User (üblicherweise der sub-Claim)

Das Backend vertraut diesen Headern nur, wenn oauth2-proxy zwingend davor geschaltet ist und unbefugte Direktzugriffe unterbunden sind (Firewall-Regel oder Bindung des Backends auf 127.0.0.1).

Integration mit Reverse-Proxy

oauth2-proxy kann auf zwei Arten eingebunden werden:

Auth-Subrequest

Apache (mod_auth_openidc oder direkter Reverse-Proxy mit mod_auth_form) und Nginx (auth_request Directive) rufen oauth2-proxy als Authentifizierungs-Subservice auf. Der Reverse-Proxy bleibt für das Request-Routing zuständig, oauth2-proxy liefert nur das Authentifizierungs-Ergebnis und Identity-Header.

Vollständiger Proxy-Durchlauf

oauth2-proxy empfängt den Request direkt (bzw. hinter einem TLS-terminierenden Reverse-Proxy, der nur durchreicht), führt die Authentifizierung durch und reicht bei Erfolg an das in upstream konfigurierte Backend weiter. Einfacher aufzusetzen, aber weniger flexibel bei Routing-Anforderungen.

Für Keycloak-Deployments der Linuxfabrik ist der Auth-Subrequest-Weg der Standard; er lässt sich mit Apache-mod_proxy konsistent mit bestehenden VirtualHost-Konfigurationen kombinieren.

Troubleshooting

Login-Loop

Häufigste Ursache: cookie_domains passt nicht zum Host oder das Cookie wird durch cookie_secure=true hinter einem HTTP-Reverse-Proxy nicht gesetzt. Mit oauth2-proxy --show-debug-on-error und dem Browser-DevTools-Network-Tab nachvollziehen, ob das Cookie am Client ankommt.

ErrEmailDomain

oauth2-proxy weist den User ab, weil die E-Mail-Domain nicht in email_domains steht. Entweder Domain ergänzen oder den Zugriff explizit auf allowed_groups beschränken und email_domains=["*"] setzen.

Cookie wird zu gross

Tritt auf, sobald das ID-Token viele Gruppen-Claims enthält. Abhilfe: session_store_type=redis mit lokaler Redis-Instanz.

User sieht Keycloak-Login trotz gültiger SSO-Session

--skip-provider-button=true überspringt die Zwischenseite von oauth2-proxy; dazu in Keycloak sicherstellen, dass der Client keinen expliziten Prompt benötigt (prompt=none bei Bedarf im IdP-URL-Template).