Files
svc-essensplanung/Doku/adr/003-single-user-mit-token.md
T
jensandClaude Opus 4.8 cb3cbfb394 M0: Skelett + Auth-Grundgerüst (Keycloak-OIDC + API-Token)
- Symfony 7.4 LTS, PHP 8.4, FrankenPHP, SQLite (3-Layer src/UI|Logic|Data)
- Auth: manueller OidcClient (Authorization-Code) im UI-Layer, kein
  Security-Bundle/league; Session-Gate via SessionAuthSubscriber
- API-Guard via statischem X-Api-Token (ApiTokenSubscriber); ExceptionSubscriber
- UserEntity (Auto-Provision) + Init-Migration
- Docker (php:8.4-frankenphp) + compose (essen.ljh31.de, traefik-net external)
- SmokeTests (7) grün: Redirect-Fälle, API-Token, Auth-Render, Logout

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-13 22:48:24 +02:00

1.9 KiB
Raw Blame History

003 – Auth: Keycloak-OIDC (Web) + statischer API-Token (HA)

Status: accepted (überarbeitet 2026-09-13; ersetzt „kein Login")

Kontext. Das Werkzeug wird im privaten Homelab von einer Person (bzw. Familie via LAN) genutzt. Es gibt bereits eine Keycloak-Instanz (https://iam.ljh31.de, Realm family), die von open-webui/webuix genutzt wird – eine Wiederverwendung ist kostenlos. Home-Assistant soll zusätzlich die API (GET /api/today) konsumieren; ein zweiter, stateless Auth-Mechanismus ist für Consumer wie HA robuster als eine Browser-Session.

Entscheidung.

  1. Web-UI: Keycloak-OIDC (Authorization-Code) gegen Realm family, eigener Client essens (Redirect https://essen.ljh31.de/auth/callback). Verifiziert wird das Id-Token (RS256 + JWKS); pro Login wird eine lokale User-Zeile auto-provisioniert (essens_user, gekoppelt an sub). Die App selbst ist ein einfaches Session-Auth-Gate (SessionAuthSubscriber): Session-Key auth_sub fehlt → Redirect /login. Kein Symfony-Security-Authenticator, keine Rollen.
  2. API: optionaler statischer Token per Header X-Api-Token (env API_TOKEN), geprüft durch ApiTokenSubscriber (nur /api/*). Token leer/leer-String → API blockiert; HA bekommt den Token direkt (kein Keycloak-Refresh-Flow im Consumer).

Konsequenzen.

    • Wiederverwendung vorhandener IdP, keine zweite Auth-Welt.
    • HA-Integration bleibt trivial (ein Header statt OIDC im Sensor).
  • − Manueller OIDC-Client (JWKS/Id-Token) statt Framework-Lib – bewusst: kein league/oauth2-client/Security-Bundle im Stack, Code bleibt klein und auditierbar.
  • − Zwei Auth-Pfade (Session + Token) – klar getrennt nach Pfad-/Header-Gate.

Abgelöst. Fassung „Single-User, keine Authentifizierung" (M0-Start) – Login via eigener Domain ohne Identität war mit HA-Kopplung und Familien-Nutzung nicht mehr akzeptabel.