Das Sitzungs-Token benannte den Benutzer ueber seinen Namen (sub = username).
Damit war der Name die Kennung der Sitzung - ein Umbenennen haette jede laufende
Anmeldung dieses Benutzers ungueltig gemacht, und deshalb war es gar nicht erst
vorgesehen. Beim Anmeldedienst geaenderte Namen liessen sich in Vorrania
folglich nirgends nachziehen.
Neue Token tragen die ID (sub = "<id>", zusaetzlich uid), und deps.py loest die
Sitzung darueber auf. Alles andere haengt ohnehin schon an der ID: Bewegungen,
Dashboards, API-Tokens. Der Name ist damit reine Anzeige.
Benutzer lassen sich jetzt unter "Benutzer" umbenennen - auch sich selbst, ohne
aus der Sitzung zu fliegen. Der Anmeldeweg selbst sucht weiterhin ueber den
Namen; das ist das Feld im Formular und soll so bleiben.
Bestandsschutz: Token ohne uid werden weiter ueber den Namen aufgeloest, damit
beim Update niemand abgemeldet wird. Der Zweig darf nach Ablauf der
Token-Lebensdauer weg. Das zusaetzliche uid unterscheidet alt von neu eindeutig -
ein Benutzer koennte schlicht "42" heissen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Neben dem Passwort-Login gibt es jetzt einen zweiten, gleichberechtigten Weg:
OpenID Connect gegen einen selbst gehosteten Anmeldedienst. Ohne Konfiguration
aendert sich nichts - keine SSO-Knoepfe, Passwort-Login wie bisher.
Der Anmeldedienst ist NUR fuer die Anmeldung zustaendig. Danach stellt Vorrania
sein eigenes Token aus wie beim Passwort-Login, deshalb bleiben deps.py, die
Rollenpruefung und die langlebigen API-Tokens unveraendert.
Backend
- Anbieter kommen aus der Umgebung (OIDC_PROVIDERS + OIDC_<KUERZEL>_*). Ein
zweiter Anbieter ist damit reine Konfiguration, ohne Codeaenderung.
- Browser-Weg (vertraulicher Client) und App-Weg (oeffentlicher Client, PKCE)
enden beide im selben Token-Schema.
- state/nonce/PKCE-Verifier liegen in einer kurzlebigen Tabelle statt in einem
Cookie: Starlettes CORS-Schicht spiegelt bei allow_origins=["*"] zusammen mit
allow_credentials die Herkunft zurueck, sobald ein Request ein Cookie traegt.
Ohne Cookie entsteht diese Wechselwirkung erst gar nicht - und der Ablauf
bleibt mit der db-Fixture pruefbar.
- Zuordnung ueber die sub des Anbieters; die Erstverknuepfung laeuft ueber die
BESTAETIGTE E-Mail-Adresse. Rollen kommen nie aus dem Anbieter, und ein
gleichlautender preferred_username uebernimmt nie ein bestehendes Konto.
- users.password_hash darf jetzt leer sein (reine SSO-Konten). verify_password
faengt das ab, sonst antwortete der Login mit 500 statt 401.
Verknuepfen bestehender Konten
- Neue Seite "Mein Konto" (fuer alle Benutzer, nicht nur Admins): verknuepfen
und wieder loesen. Die Berechtigung stammt aus der laufenden Sitzung, es
braucht also weder eine hinterlegte Adresse noch Admin-Rechte.
- Der Start laeuft ueber POST, weil eine Seitennavigation das Bearer-Token
nicht mitschicken kann.
- Die letzte Anmeldemoeglichkeit eines Kontos laesst sich nicht loesen.
iOS
- AppAuth (erste Paketabhaengigkeit) mit PKCE im System-Browser, nie in einem
eingebetteten WebView, und ohne Client-Secret.
- offline_access nur im App-Weg: der Browser-Weg braucht kein Refresh-Token und
bekaeme sonst einen ueberfluessigen Zustimmungsdialog.
- Anmeldezustand je Serverprofil im Keychain; abgelaufene Token erneuert die App
still im Hintergrund. Gleichzeitige 401er teilen sich eine Erneuerung.
Deployment
- docker-compose reicht die ganze .env durch. Einzeln aufzuzaehlen ginge nur mit
fest verdrahteten Kuerzeln - genau das soll ein weiterer Anbieter nicht
erfordern.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>