fix(auth): erneuter Login-Tap oeffnet zuverlaessig wieder den Browser

Nach fehlgeschlagenem/timeout Login blieb der Browser beim naechsten Tap
zu: ein per UI-Timeout verwaister flutter_appauth-Flow blockierte nativ
('Connection already in progress').

- Provider dedupet login() (nur EIN authorizeAndExchangeCode gleichzeitig,
  race-sicher via identical-Guard) + discardPendingLogin() gibt die Sperre
  nach UI-Timeout frei, damit der naechste Tap frisch startet
- Best-Effort-Retry, falls der native Flow noch offen ist
- AuthBloc: discardPendingLogin() bei Timeout; kein zweiter Handler waehrend
  Authenticating

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dennis Nemec
2026-09-01 16:06:58 +02:00
parent 7b7cb4eb63
commit 83d52364a5
2 changed files with 89 additions and 21 deletions

View File

@ -60,6 +60,9 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
LoginRequested event,
Emitter<AuthState> emit,
) async {
// Läuft bereits ein interaktiver Login (Spinner sichtbar), keinen
// zweiten Flow starten. Der Provider dedupet zusätzlich nativ.
if (state is Authenticating) return;
try {
emit(Authenticating());
await tokenProvider.login().timeout(_loginTimeout);
@ -72,7 +75,12 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
// State dann auf `Authenticated`. Kein Schaden, nur „nachträgliche
// Anmeldung". Bei späterer Exception passiert nichts; das Future
// ist hier nicht mehr awaited.
//
// Wichtig: die Dedup-Sperre im Provider freigeben, sonst würde der
// nächste „Anmelden"-Tap denselben (aufgegebenen) Flow wiederver-
// wenden statt einen frischen Browser-Tab zu öffnen.
debugPrint('Login-Timeout nach ${_loginTimeout.inSeconds}s.');
tokenProvider.discardPendingLogin();
emit(Unauthenticated(loginTimedOut: true));
} catch (err, st) {
debugPrint('Login fehlgeschlagen: $err\n$st');