E-Mail-Verifizierung & Multi-Faktor-Authentifizierung
Eine perfekte Token-Pipeline nützt nichts, wenn die falsche Person ein Token erhalten kann. Wittgenstein kombiniert deshalb seine Bibliotheken zur Token-Verarbeitung mit starker Identitätssicherung am Identity Provider: Jedes Konto ist an eine verifizierte E-Mail-Adresse gebunden, und sensibler Zugriff erfordert einen zweiten Faktor.
Nichts davon steckt im Anwendungscode. Es wird von Keycloak erzwungen, bevor überhaupt ein Token ausgestellt wird — jede Anwendung der Plattform erbt es und kann es nicht versehentlich abschwächen.
Die Sicherungsleiter
| Stufe | Was Keycloak nachweist | Durchgesetzt durch |
|---|---|---|
| 1 — Verifizierte Identität | Der Benutzer kontrolliert das hinterlegte Postfach | Required Action VERIFY_EMAIL |
| 2 — Verifizierte Identität + Besitz | …und besitzt einen registrierten zweiten Faktor | TOTP-Authenticator oder WebAuthn / Passkey |
| Wiederherstellung | Ein verlorener Faktor oder ein Passwort lässt sich zurücksetzen, ohne dass ein Administrator ein Geheimnis anfasst | Signierte, ablaufende E-Mail-Aktionslinks |
Anwendungen lesen die erreichte Stufe aus dem Token (Claim acr) und entscheiden, was jede Route verlangt.
E-Mail-Verifizierung
Konten werden unverifiziert angelegt. Solange der Benutzer den Besitz der Adresse nicht nachweist, schließt Keycloak den Login nicht ab — die Required Action VERIFY_EMAIL unterbricht den Ablauf und versendet einen signierten Link.
sequenceDiagram
participant U as Benutzer
participant KC as Keycloak
participant SMTP as Mail-Relay
participant M as Postfach
U->>KC: Erster Login (Passwort)
KC->>KC: Required Action: VERIFY_EMAIL
KC->>SMTP: Verifizierungs-E-Mail (signierter, ablaufender Link)
SMTP->>M: Zustellung über authentifiziertes TLS
U->>M: Öffnet die Nachricht, klickt auf den Link
M->>KC: GET action-token
KC->>KC: emailVerified = true
KC-->>U: Login wird fortgesetzt → Token ausgestellt
Warum das wichtig ist:
- Verhindert Tippfehler- und Squatting-Konten — niemand kann eine Adresse registrieren, die ihm nicht gehört.
- Macht E-Mail zu einem vertrauenswürdigen Wiederherstellungskanal — Passwort- und Faktor-Resets gehen an ein nachgewiesenes Postfach, nicht an eine bloß eingetippte Adresse.
- Macht
email-Claims verwendbar — Dienste können sich beim Verknüpfen oder Provisionieren von Identitäten aufemail_verifiedverlassen.
Die Zustellung übernimmt das plattformeigene authentifizierte SMTP-Relay, sodass Verifizierungs-Mails nicht von Dritten abhängen.
Multi-Faktor-Authentifizierung
Der Browser-Flow von Keycloak wird um einen zweiten Faktor erweitert. Unterstützte Faktoren:
| Faktor | Typ | Hinweise |
|---|---|---|
| TOTP | Authenticator-App (jede RFC-6238-App) | Einrichtung über die Required Action CONFIGURE_TOTP |
| WebAuthn / Passkeys | Hardware-Schlüssel, Plattform-Authenticator | Phishing-resistent: Die Anmeldeinformation ist an den Origin der Website gebunden |
| Wiederherstellungscodes | Einmalcodes | Offline-Rückfall bei Geräteverlust |
MFA lässt sich als Richtlinie statt als Einstellung pro Benutzer anwenden:
- Immer — für alle Benutzer des Realms.
- Nach Rolle oder Gruppe — z. B. wird jeder mit einer administrativen Rolle abgefragt, Nur-Lese-Benutzer nicht (bedingte Flows in Keycloak).
- Step-up — der Benutzer ist auf Stufe 1 angemeldet und wird erst dann nach dem zweiten Faktor gefragt, wenn er etwas erreicht, das Stufe 2 verlangt.
Step-up in Ihrer API erzwingen
Keycloak hält die Authentifizierungsstufe im Claim acr fest. Da OidcMiddleware das Token der Anfrage bereits geparst hat, kann eine Route die stärkere Stufe in wenigen Zeilen verlangen:
from fastapi import Depends, HTTPException
from wittgenstein_oidc_backend import get_current_payload
def require_mfa(payload: dict = Depends(get_current_payload)) -> dict:
if int(payload.get("acr", "0")) < 2: # 2 = Passwort + zweiter Faktor
raise HTTPException(
status_code=401,
detail="step-up required",
headers={"WWW-Authenticate": 'Bearer error="insufficient_user_authentication"'},
)
return payload
@app.delete("/tenants/{tenant_id}", dependencies=[Depends(require_mfa)])
async def delete_tenant(tenant_id: str): ...
Die SPA reagiert auf diese Antwort mit einem Redirect zu Keycloak mit acr_values=2; der Benutzer schließt den zweiten Faktor ab und kehrt mit einem Token zurück, das die Route erfüllt.
E-Mail-Aktionslinks
Sensible Kontoänderungen laufen nie über die Anwendung. Um ein Passwort zu ändern, bittet die App Keycloak, dem Benutzer einen Required-Action-Link zu mailen; der Benutzer wählt das neue Passwort auf der eigenen Seite von Keycloak, wo Passwortrichtlinie und Brute-Force-Schutz greifen. Die Anwendung sieht, speichert oder überträgt das Passwort nie.
Derselbe Mechanismus kann CONFIGURE_TOTP (Faktor neu einrichten), VERIFY_EMAIL (erneut verifizieren) oder UPDATE_PROFILE anfordern. Die Links sind signiert, zweckgebunden und kurzlebig.
Minimale Rechte für den Aufrufer
Der Dienst, der diese E-Mails auslöst, nutzt einen dedizierten Service-Account-Client mit nur den benötigten Realm-Management-Rollen (view-users, manage-users), nie mit einer vollständigen Administrator-Berechtigung.
Härtung von Sitzung und Sperre
Die Sicherung ist nur so stark wie die Sitzung, die darauf folgt:
- Kurzlebige Access-Tokens (Minuten), mit gleitendem Idle-Timeout und absolutem Sitzungsmaximum.
- Rotation des Refresh-Tokens, das in einem
HttpOnly-Cookie liegt (siehe OIDC & Token-Sicherheit). - Brute-Force-Erkennung sperrt ein Konto nach wiederholten Fehlversuchen vorübergehend, sodass ein zweiter Faktor nicht durch Raten ausgehebelt werden kann.
- Passwortrichtlinie (Länge, Historie, Sperrliste), von Keycloak an einer einzigen Stelle ausgewertet.
Konfiguration prüfen
"0",
"1",
"2"
]curl -s -H "Authorization: Bearer $TOKEN" https://app.example.com/api/tenants/t-1 -X DELETE -o /dev/null -w "%{http_code}\n"401# ein Stufe-1-Token wird an einer Stufe-2-Route abgewiesen, bis der Benutzer MFA abschließt
MFA sicher einführen
Beginnen Sie mit den administrativen Rollen, prüfen Sie, dass Wiederherstellungscodes und E-Mail-Links durchgängig funktionieren, und weiten Sie die Richtlinie erst dann aus. Da die Durchsetzung im IdP liegt, erfordert die Ausweitung nie ein Deployment einer Anwendung.