# 0005 — Keycloak SSO mit Dev-Bypass für Read/Write-Trennung

| | |
|---|---|
| **Status** | accepted |
| **Datum** | 2026-04-10 |
| **Refs** | Issue #43, Commit 7159240 + 303b30f, app/auth.py |

## Kontext

Die Webapp soll öffentlich durchsuchbar sein (Assessments lesen, PDFs
ansehen, Auswertungen), aber Analyse-Aktionen (Antrag bewerten, Programme
indexieren) nur authentifizierten Nutzern erlauben. Der User betreibt
bereits einen Keycloak-Server unter `sso.toppyr.de` mit Realm `collaboration`.

## Optionen

### Option A — Keycloak-only mit hartem 401

Alle POST-Endpoints erfordern JWT. Ohne Keycloak-Server läuft nichts.

**Vorteile:** Klar, sicher.
**Nachteile:** Lokale Entwicklung blockiert ohne Keycloak-Instanz.

### Option B — Dev-Bypass: Auth nur wenn ENV gesetzt

Wenn `KEYCLOAK_URL` leer ist → ALLE Endpoints offen (Dev-Modus).
Wenn gesetzt → POST-Endpoints erfordern JWT, GET bleibt offen.

**Vorteile:** Lokale Dev ohne Keycloak. Prod sofort sicher per ENV.
**Nachteile:** Versehentlich Prod ohne ENV = alles offen.

### Option C — API-Key statt Keycloak

Einfacher API-Key-Header für POST-Endpoints.

**Vorteile:** Zero-Dependency.
**Nachteile:** Kein SSO, kein User-Identity, keine Gruppen/Rollen.

## Entscheidung

**Option B.** Dev-Bypass ermöglicht reibungslose lokale Entwicklung und
Batch-Skripte (die keinen JWT haben). Prod-Absicherung über die drei
ENV-Vars in docker-compose.yml. Die Keycloak-Client-Registrierung in
`sso.toppyr.de` ist ein einmaliger manueller Schritt.

## Implementation

- `app/auth.py`: JWKS-Cache (1h TTL), `get_current_user` (optional),
  `require_auth` (pflicht), `keycloak_login_url` (für Browser-Redirect)
- POST-Endpoints (`/analyze`, `/api/analyze-drucksache`,
  `/api/programme/index`): `user: dict = Depends(require_auth)`
- GET-Endpoints: unverändert offen
- Frontend: `initAuth()` prüft `/api/auth/me`, steuert
  "Jetzt prüfen"-Button (disabled + Tooltip wenn nicht eingeloggt)
  und "Anmelden"-Button im Header

## Konsequenzen

### Positiv

- Read-Only für alle, Write nur mit Login — klare Trennung
- Batch-Skripte und auto-Re-Analyse im Container laufen im Dev-Modus
  (KEYCLOAK_URL nicht gesetzt), keine Auth-Hürde für Maintenance
- Keycloak-Rollen über `realm_access.roles` im JWT verfügbar für
  künftige Gruppen-Features (#94 Bookmarks/Kommentare)

### Negativ

- Dev-Modus ist unsicher — wenn jemand KEYCLOAK_URL in Prod vergisst
  zu setzen, ist alles offen. Mitigation: Health-Endpoint oder
  Startup-Warning wenn ENV fehlt.
- JWKS-Cache (1h) bedeutet: nach Key-Rotation dauert es bis zu 1h bis
  alte Tokens abgelehnt werden. Für dieses Projekt akzeptabel.

### Folgen für andere ADRs

- #94 Bookmarks/Kommentare baut auf der User-Identity aus dem JWT auf
  (`sub`, `email`, `realm_access.roles`).
- #95 Queuing könnte Auth-User priorisieren.
