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
@@ -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.