···1515 /// Gets the current user's handle
1616 String? get handle;
17171818+ /// Gets the saved handle from the last persisted session, if available
1919+ String? get lastKnownHandle;
2020+1821 /// Gets the current user's PDS endpoint
1922 String? get pdsEndpoint;
2023
···10001000 /// **'Enter your handle to continue with OAuth'**
10011001 String get messageEnterHandle;
1002100210031003+ /// Title for auth recovery page when a saved session could not be verified
10041004+ ///
10051005+ /// In en, this message translates to:
10061006+ /// **'Sign in again'**
10071007+ String get pageTitleSignInAgain;
10081008+10091009+ /// Explanation on auth recovery page after saved session verification fails
10101010+ ///
10111011+ /// In en, this message translates to:
10121012+ /// **'We found your saved account, but your session could not be verified. You can sign in again with this handle or go back to get started.'**
10131013+ String get messageSavedSessionRecovery;
10141014+10151015+ /// Button label for continuing OAuth with a prefilled handle
10161016+ ///
10171017+ /// In en, this message translates to:
10181018+ /// **'Continue as {handle}'**
10191019+ String buttonContinueAs(String handle);
10201020+10211021+ /// Button label to leave auth recovery and open the normal get started page
10221022+ ///
10231023+ /// In en, this message translates to:
10241024+ /// **'Go to get started'**
10251025+ String get buttonGoToGetStarted;
10261026+10271027+ /// Validation error when handle field is empty
10281028+ ///
10291029+ /// In en, this message translates to:
10301030+ /// **'Enter your handle'**
10311031+ String get errorEnterHandle;
10321032+10331033+ /// Error message when OAuth sign in fails
10341034+ ///
10351035+ /// In en, this message translates to:
10361036+ /// **'Sign in failed: {details}'**
10371037+ String errorSignInFailed(String details);
10381038+10031039 /// Loading message when completing sign up
10041040 ///
10051041 /// In en, this message translates to:
+23
lib/src/core/l10n/app_localizations_en.dart
···488488 String get messageEnterHandle => 'Enter your handle to continue with OAuth';
489489490490 @override
491491+ String get pageTitleSignInAgain => 'Sign in again';
492492+493493+ @override
494494+ String get messageSavedSessionRecovery =>
495495+ 'We found your saved account, but your session could not be verified. You can sign in again with this handle or go back to get started.';
496496+497497+ @override
498498+ String buttonContinueAs(String handle) {
499499+ return 'Continue as $handle';
500500+ }
501501+502502+ @override
503503+ String get buttonGoToGetStarted => 'Go to get started';
504504+505505+ @override
506506+ String get errorEnterHandle => 'Enter your handle';
507507+508508+ @override
509509+ String errorSignInFailed(String details) {
510510+ return 'Sign in failed: $details';
511511+ }
512512+513513+ @override
491514 String get messageCompletingSignUp => 'Completing sign up...';
492515493516 @override
+40
lib/src/core/l10n/intl_en.arb
···797797 "description": "Message to enter handle for OAuth"
798798 },
799799800800+ "pageTitleSignInAgain": "Sign in again",
801801+ "@pageTitleSignInAgain": {
802802+ "description": "Title for auth recovery page when a saved session could not be verified"
803803+ },
804804+805805+ "messageSavedSessionRecovery": "We found your saved account, but your session could not be verified. You can sign in again with this handle or go back to get started.",
806806+ "@messageSavedSessionRecovery": {
807807+ "description": "Explanation on auth recovery page after saved session verification fails"
808808+ },
809809+810810+ "buttonContinueAs": "Continue as {handle}",
811811+ "@buttonContinueAs": {
812812+ "description": "Button label for continuing OAuth with a prefilled handle",
813813+ "placeholders": {
814814+ "handle": {
815815+ "type": "String"
816816+ }
817817+ }
818818+ },
819819+820820+ "buttonGoToGetStarted": "Go to get started",
821821+ "@buttonGoToGetStarted": {
822822+ "description": "Button label to leave auth recovery and open the normal get started page"
823823+ },
824824+825825+ "errorEnterHandle": "Enter your handle",
826826+ "@errorEnterHandle": {
827827+ "description": "Validation error when handle field is empty"
828828+ },
829829+830830+ "errorSignInFailed": "Sign in failed: {details}",
831831+ "@errorSignInFailed": {
832832+ "description": "Error message when OAuth sign in fails",
833833+ "placeholders": {
834834+ "details": {
835835+ "type": "String"
836836+ }
837837+ }
838838+ },
839839+800840 "messageCompletingSignUp": "Completing sign up...",
801841 "@messageCompletingSignUp": {
802842 "description": "Loading message when completing sign up"
+7-3
lib/src/core/routing/app_router.dart
···30303131 try {
3232 await authRepository.initializationComplete;
3333- final hadSavedSession = authRepository.did?.isNotEmpty ?? false;
3333+ final savedHandle = authRepository.lastKnownHandle?.trim();
3434+ final hadSavedSession = savedHandle != null && savedHandle.isNotEmpty;
3435 final isSessionValid = await authRepository.validateSession();
35363637 if (!isSessionValid) {
3738 _logger.i(
3839 hadSavedSession
3939- ? 'Redirecting to login because the saved session is no longer valid'
4040+ ? 'Redirecting to auth recovery because the saved session could not be verified'
4041 : 'Redirecting to register because the user is not signed in',
4142 );
4243 resolver.redirectUntil(
4343- hadSavedSession ? const LoginRoute() : const RegisterRoute(),
4444+ hadSavedSession
4545+ ? AuthRecoveryRoute(handle: savedHandle)
4646+ : const RegisterRoute(),
4447 );
4548 return;
4649 }
···177180178181 // Alternate starting routes
179182 AutoRoute(page: EmptyRoute.page, path: '/empty'),
183183+ AutoRoute(page: AuthRecoveryRoute.page, path: '/auth/recover'),
180184 AutoRoute(page: LoginRoute.page, path: '/login'),
181185 AutoRoute(page: RegisterRoute.page, path: '/register'),
182186 AutoRoute(page: OnboardingRoute.page, path: '/onboarding/profile'),