[Bug] Auth: abgelaufener ID-Token zeigt rohen JS-Stacktrace statt Silent-Refresh oder Re-Login #404

Closed
opened 2026-05-25 11:17:03 +02:00 by pm-bot · 1 comment
Collaborator

Beobachtung

Beim Öffnen der Web-App (app.mrrm.de/lists) erscheint prominent als rote User-facing Box ein roher JavaScript-Stacktrace:

UNHANDLED PROMISE: Error: ID token expired
    at v2 (https://app.mrrm.de/assets/index-BoOML86G.js:112:145835)
    at async oie.getUser (https://app.mrrm.de/assets/index-BoOML86G.js:112:150947)

Die App rendert die Listen darunter trotzdem — die Seite ist also nicht komplett kaputt, nur das Auth-State-Handling beim Initial-Load.

Stand: 2026-05-25 11:13 (Stakeholder-Report mit Screenshot).

Erwartetes Verhalten

Bei abgelaufenem ID-Token sollte einer dieser zwei Pfade greifen:

  • A) Silent Refresh: Refresh-Token nutzen um einen neuen ID-Token zu holen, ohne dass der User etwas merkt
  • B) Re-Login-Redirect: Wenn Refresh nicht möglich, direkt zur Login-Seite mit ?returnTo=…, nicht mit Stacktrace im UI

In keinem Fall darf ein roher Stacktrace User-facing erscheinen.

Aktuelles Verhalten

  • oie.getUser wirft Error: ID token expired
  • Die Promise-Rejection wird nicht gefangen
  • Globale Error-Boundary / Toast-Layer zeigt den Raw-Error
  • Listen-Daten kommen trotzdem (vermutlich aus Cache oder mit altem Token, der nur auf der Auth-Layer aber nicht auf der API-Layer geprüft wird — das ist ein separater Konsistenz-Bug)

Zwei Bugs in einem

  1. Auth-Refresh fehlt — abgelaufener ID-Token wird nicht erneuert
  2. Error-Handling fehlt — unhandled promise rejection landet im UI als Stacktrace

Beide sollten zusammen gefixt werden, da das Fehlen von (2) den Schaden von (1) erst sichtbar macht.

Reproduktion

  • Web-App öffnen wenn der ID-Token vor längerer Zeit ausgestellt wurde (>Token-Lifetime)
  • Initial-Render löst getUser aus → Fehler

Impact

  • User-facing: Vertrauensschaden, „App ist kaputt"-Eindruck obwohl funktional
  • Häufigkeit: Vermutlich jedes Mal wenn ein User die App nach längerer Pause öffnet
  • Workaround: Seite reloaden + neu einloggen

Mögliche Ursache (Anmerkung PM, kein Tech-Call)

Build-Hash index-BoOML86G.js ist der aktuelle Prod-Build nach dem Versions-Sync-Merge gestern Abend (PR #401, Commit 710c785). Sehr unwahrscheinlich dass die Versions-Sync das eingeführt hat — der Auth-Code wurde dort nicht angefasst. Aber wert zu verifizieren ob das vor dem Merge auch schon passiert ist.

Akzeptanzkriterien

  • Abgelaufener ID-Token triggert Silent-Refresh (falls Refresh-Token gültig)
  • Fallback: Redirect zur Login-Seite mit Return-URL
  • Globale unhandled-promise-Boundary verhindert Raw-Stacktrace im UI
  • Test: Token künstlich invalidieren → kein Stacktrace, Re-Login klappt
## Beobachtung Beim Öffnen der Web-App (`app.mrrm.de/lists`) erscheint **prominent als rote User-facing Box** ein roher JavaScript-Stacktrace: ``` UNHANDLED PROMISE: Error: ID token expired at v2 (https://app.mrrm.de/assets/index-BoOML86G.js:112:145835) at async oie.getUser (https://app.mrrm.de/assets/index-BoOML86G.js:112:150947) ``` Die App rendert die Listen darunter trotzdem — die Seite ist also nicht komplett kaputt, nur das Auth-State-Handling beim Initial-Load. Stand: 2026-05-25 11:13 (Stakeholder-Report mit Screenshot). ## Erwartetes Verhalten Bei abgelaufenem ID-Token sollte einer dieser zwei Pfade greifen: - **A) Silent Refresh:** Refresh-Token nutzen um einen neuen ID-Token zu holen, ohne dass der User etwas merkt - **B) Re-Login-Redirect:** Wenn Refresh nicht möglich, direkt zur Login-Seite mit `?returnTo=…`, **nicht** mit Stacktrace im UI In keinem Fall darf ein roher Stacktrace User-facing erscheinen. ## Aktuelles Verhalten - `oie.getUser` wirft `Error: ID token expired` - Die Promise-Rejection wird nicht gefangen - Globale Error-Boundary / Toast-Layer zeigt den Raw-Error - Listen-Daten kommen trotzdem (vermutlich aus Cache oder mit altem Token, der nur auf der Auth-Layer aber nicht auf der API-Layer geprüft wird — das ist ein **separater** Konsistenz-Bug) ## Zwei Bugs in einem 1. **Auth-Refresh fehlt** — abgelaufener ID-Token wird nicht erneuert 2. **Error-Handling fehlt** — unhandled promise rejection landet im UI als Stacktrace Beide sollten zusammen gefixt werden, da das Fehlen von (2) den Schaden von (1) erst sichtbar macht. ## Reproduktion - Web-App öffnen wenn der ID-Token vor längerer Zeit ausgestellt wurde (>Token-Lifetime) - Initial-Render löst `getUser` aus → Fehler ## Impact - **User-facing:** Vertrauensschaden, „App ist kaputt"-Eindruck obwohl funktional - **Häufigkeit:** Vermutlich jedes Mal wenn ein User die App nach längerer Pause öffnet - **Workaround:** Seite reloaden + neu einloggen ## Mögliche Ursache (Anmerkung PM, kein Tech-Call) Build-Hash `index-BoOML86G.js` ist der aktuelle Prod-Build nach dem Versions-Sync-Merge gestern Abend (PR #401, Commit `710c785`). **Sehr unwahrscheinlich** dass die Versions-Sync das eingeführt hat — der Auth-Code wurde dort nicht angefasst. Aber wert zu verifizieren ob das vor dem Merge auch schon passiert ist. ## Akzeptanzkriterien - [ ] Abgelaufener ID-Token triggert Silent-Refresh (falls Refresh-Token gültig) - [ ] Fallback: Redirect zur Login-Seite mit Return-URL - [ ] Globale unhandled-promise-Boundary verhindert Raw-Stacktrace im UI - [ ] Test: Token künstlich invalidieren → kein Stacktrace, Re-Login klappt
Author
Collaborator

QA-Reproduzier-Rezept (Vorschlag)

QA-Hut, gepostet via pm-bot. Damit Smoke-Test reproduzierbar ist:

Browser-DevTools (Web)

  1. App öffnen, einloggen
  2. DevTools → Application → Local/Session-Storage bzw. Cookies
  3. ID-Token-Eintrag finden (vermutlich Auth0/OIDC-Schlüssel)
  4. Token-Payload manuell mit abgelaufenem exp ersetzen — per jwt.io ein Token mit exp < now() generieren. Signatur darf gefälscht sein, wir testen Client-Verhalten, nicht Server-Validierung.
  5. Reload → erwartet: Silent-Refresh oder Login-Redirect, kein Stacktrace im UI

Alternative: Time-Travel

  • Browser-System-Zeit auf +2h stellen → ID-Token läuft echt ab → Reload

Mobile Native (falls Auth-Stack identisch)

  • Analog im Native-Storage, oder App 1h+ im Background lassen, dann öffnen

Akzeptanz für #404-Fix

  • Stacktrace-Box erscheint nicht (kein User-facing Raw-Error)
  • Entweder Silent-Refresh (User merkt nichts) oder Login-Redirect mit returnTo
  • Listen werden nach Refresh/Re-Login korrekt nachgeladen (kein API-Cache-Drift — der API-Konsistenz-Teil ist separat als eigenes Issue ausgegliedert)

Reihenfolge fürs Smoke-Sign-off siehe Kommentar in #405.

## QA-Reproduzier-Rezept (Vorschlag) _QA-Hut, gepostet via pm-bot. Damit Smoke-Test reproduzierbar ist:_ ### Browser-DevTools (Web) 1. App öffnen, einloggen 2. DevTools → Application → Local/Session-Storage bzw. Cookies 3. ID-Token-Eintrag finden (vermutlich Auth0/OIDC-Schlüssel) 4. Token-Payload manuell mit abgelaufenem `exp` ersetzen — per jwt.io ein Token mit `exp` < `now()` generieren. Signatur darf gefälscht sein, wir testen Client-Verhalten, nicht Server-Validierung. 5. Reload → erwartet: Silent-Refresh **oder** Login-Redirect, **kein** Stacktrace im UI ### Alternative: Time-Travel - Browser-System-Zeit auf `+2h` stellen → ID-Token läuft echt ab → Reload ### Mobile Native (falls Auth-Stack identisch) - Analog im Native-Storage, oder App 1h+ im Background lassen, dann öffnen ### Akzeptanz für #404-Fix - [ ] Stacktrace-Box erscheint nicht (kein User-facing Raw-Error) - [ ] Entweder Silent-Refresh (User merkt nichts) **oder** Login-Redirect mit `returnTo` - [ ] Listen werden nach Refresh/Re-Login korrekt nachgeladen (kein API-Cache-Drift — der API-Konsistenz-Teil ist separat als eigenes Issue ausgegliedert) Reihenfolge fürs Smoke-Sign-off siehe Kommentar in #405.
admin-mrrm referenced this issue from a commit 2026-05-27 05:53:09 +02:00
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
admin-mrrm/mrrmlabapp#404
No description provided.