feat: implement OIDC PKCE flow for Keycloak login with frontend-client

Completed OIDC Authorization Code Flow with PKCE (S256) for JS and JVM platforms.
- Added `launchOidcFlow`, `consumePendingOidcCallback`, and `getOidcRedirectUri` with platform-specific implementations.
- Integrated SHA-256 and Base64URL helpers for PKCE.
- Updated `LoginViewModel` with OIDC logic (key handling, token exchange, state validation).
- Enhanced `LoginScreen` with an OIDC login button and loading spinner.
- Verified implementation with system hardening roadmap tasks.

Includes browser redirects for JS, localhost HTTP callback for JVM, and built-in Keycloak URL construction.

Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
2026-03-09 11:54:35 +01:00
parent 2db3fd82c5
commit b9a433f772
12 changed files with 662 additions and 44 deletions
@@ -57,7 +57,8 @@ Anbindung des Frontends an den neuen Service.
### 3.1 HTTP Client & Sync (Frontend Expert)
- [ ] **Ktor Client:** Konfiguration des HTTP-Clients für die Kommunikation mit dem Gateway (`http://localhost:8080`).
- [ ] **Auth:** Implementierung des OIDC-Flows im Frontend (Login via Keycloak), Speichern des Tokens.
- [x] **Auth:** Implementierung des OIDC-Flows im Frontend (Login via Keycloak), Speichern des Tokens. _(verifiziert
2026-03-09: PKCE S256 + frontend-client + JVM/JS actual-Implementierungen)_
- [ ] **Integration:** Aufruf von `/api/ping` und `/api/ping/secure` und Anzeige im UI.
### 3.2 Offline-Sync Basis (Frontend Expert)
@@ -68,5 +68,10 @@ last_update: 2026-03-09
- Prüfen der `kotlinx-browser` Version.
### 3.2 Auth Integration
- [ ] **OIDC Client:** _(offen — abhängig von Keycloak Härtung)_
- Implementierung des Login-Flows mit `ktor-client-auth` und Keycloak.
- [x] **OIDC Client:** _(verifiziert 2026-03-09)_
- PKCE Authorization Code Flow (S256) mit `frontend-client`.
- Pure Kotlin SHA-256 + PkceHelper (commonMain, kein expect/actual).
- JVM: lokaler Callback-Server (Port 18080) + `Desktop.browse()`.
- JS: Seiten-Redirect + URL-Parsing beim App-Start + `replaceState`-Bereinigung.
- `LoginViewModel` + `LoginScreen` um OIDC-Button erweitert.
@@ -74,7 +74,44 @@ Propagation-Konfiguration im Gateway.
- Redundante direkte `micrometer-tracing-bridge-brave`-Dependency entfernt
(bereits transitiv via `monitoring-client` vorhanden).
## ✅ OIDC Client im Frontend (2026-03-09, gleiche Session)
Login-Flow mit PKCE Authorization Code Flow (S256) für `frontend-client` implementiert.
### Neue Dateien
- **`frontend/core/auth/src/commonMain/.../Sha256.kt`**: Pure Kotlin SHA-256 (FIPS 180-4) + Base64URL-Encoding — kein
expect/actual, läuft auf JVM/JS/Wasm.
- **`frontend/core/auth/src/commonMain/.../PkceHelper.kt`**: Code Verifier, Code Challenge (S256), State Generator.
- **`frontend/core/auth/src/commonMain/.../OidcCallback.kt`**: `OidcCallbackResult` sealed class + expect
`launchOidcFlow()`, `consumePendingOidcCallback()`, `getOidcRedirectUri()`.
- **`frontend/core/auth/src/jvmMain/.../OidcCallback.jvm.kt`**: Eingebetteter `HttpServer` (Port 18080) +
`Desktop.browse()` + `CompletableDeferred` (Timeout 5 min).
- **`frontend/core/auth/src/jsMain/.../OidcCallback.js.kt`**: `window.location.href` Redirect + URL-Parameter-Parsing
beim App-Start + History-Bereinigung via `replaceState`.
### Geänderte Dateien
- **`frontend/core/domain/.../AppConstants.kt`**: `KEYCLOAK_CLIENT_ID``frontend-client`, OIDC-Konstanten ergänzt.
- **`frontend/core/auth/src/commonMain/.../AuthApiClient.kt`**: `buildAuthorizationUrl()` (PKCE URL-Builder) +
`exchangeCodeForToken()` (Code → Token).
- **`frontend/core/auth/src/commonMain/.../LoginViewModel.kt`**: `isOidcLoading`-State, `startOidcFlow()`,
`handleOidcCallbackResult()`, JS-Init-Callback-Check.
- **`frontend/core/auth/src/commonMain/.../LoginScreen.kt`**: Divider + `OutlinedButton` „Mit Keycloak anmelden" mit
Spinner bei laufendem Flow.
### Architektur-Entscheidungen
- **Kein `ktor-client-auth`**: Der OIDC-Flow wird manuell implementiert — `ktor-client-auth` unterstützt Authorization
Code + PKCE nicht nativ für KMP.
- **Pure Kotlin SHA-256**: Kein `expect/actual` nötig — `kotlin.math` + reine Bitoperationen reichen aus.
- **JVM-Callback-Server** auf `localhost:18080`: Standard-Muster für Desktop-Apps (RFC 8252 „OAuth 2.0 for Native
Apps").
- **JS-Redirect-Flow**: Kein Popup — volle Seitenweiterleitung. Code Verifier wird in `sessionStorage` gespeichert (nur
aktueller Tab).
- **State-Validierung**: CSRF-Schutz via State-Parameter-Vergleich im ViewModel.
## 🔜 Nächste Schritte
- **OIDC Client im Frontend** — Login-Flow mit `ktor-client-auth` und `frontend-client` implementieren.
- **TLS/HTTPS** — Langfristig: `KC_HOSTNAME_STRICT_HTTPS=true` setzen, sobald TLS eingerichtet ist.
- **Gateway CircuitBreaker** — Verifizieren ob durch Spring Cloud 2025.0.1 bereits behoben.