Problem: I’m using GoRouter with a GoRouterRefreshStream that listens to my AuthCubit.stream (Cubit emits states like Authenticated, UnAuthenticated, etc.).
Everything works fine when logging in or navigating between screens, the router reacts correctly to auth state changes. But when I press logout, the app stays on the protected page (ProfileScreen) instead of redirecting to Home or Login.
After pressing logout: -The Cubit emits UnAuthenticated -The stream listener calls notifyListeners()
But the redirect doesn’t run, and I’m still stuck on /profile. If I manually add context.go(Routes.homeScreen) inside the button, it works, but I’d like this to happen automatically via GoRouter redirect, not manually in the UI.
i have tried even simple IF statement:
if (authCubit.state is! Authenticated) {
return Routes.homeScreen;
}
and not working :(
My router:
final _rootNavigatorKey = GlobalKey<NavigatorState>();
final _shellNavigatorKey = GlobalKey<NavigatorState>();
GoRouter buildRouter(AuthCubit authCubit) {
return GoRouter(
navigatorKey: _rootNavigatorKey,
initialLocation: Routes.homeScreen,
refreshListenable: GoRouterRefreshStream(authCubit.stream),
redirect: (context, state) {
final s = authCubit.state;
final loc = state.matchedLocation;
final isAuthed = s is Authenticated;
final emailNotVerified = s is EmailNotVerified;
final needsCompletion = s is AuthNeedsCompletion;
final isLoading = s is AuthLoading;
if (isLoading) return null;
final atLoginOrRegister = loc == Routes.loginScreen || loc == Routes.registerScreen;
final atVerify = loc == Routes.verifyEmailScreen;
final atComplete = loc == Routes.authCompleteScreen;
final atAuthFlow = atLoginOrRegister || atVerify || atComplete;
final atProfile = loc == Routes.profileScreen;
final wantsProtected = loc.startsWith(Routes.profileScreen);
if (authCubit.state is! Authenticated && state.uri.path == Routes.profileScreen) {
return Routes.homeScreen;
}
if (emailNotVerified && !atVerify) {
return Routes.verifyEmailScreen;
}
if (needsCompletion && !atComplete) {
return Routes.authCompleteScreen;
}
if (!isAuthed && wantsProtected) {
return Routes.loginScreen;
}
if (isAuthed && atAuthFlow && !atProfile) {
return Routes.profileScreen;
}
return null;
},
routes: [
GoRoute(
parentNavigatorKey: _rootNavigatorKey,
path: Routes.loginScreen,
builder: (context, state) {
final extras = state.extra as Map<String, dynamic>?;
final token = extras?['token'] ?? 0;
return LoginScreen(
key: ValueKey('login-$token'),
togglePages: () => context.replace(Routes.registerScreen),
extras: extras,
);
},
routes: [GoRoute(path: 'forgotPassword', builder: (context, state) => const ForgottenPasswordScreen())],
),
GoRoute(
parentNavigatorKey: _rootNavigatorKey,
path: Routes.registerScreen,
builder: (context, state) => RegisterScreen(togglePages: () => context.replace(Routes.loginScreen)),
),
GoRoute(
path: Routes.profileScreen,
parentNavigatorKey: _rootNavigatorKey,
builder: (context, state) => const ProfileScreen(),
),
GoRoute(
path: Routes.authCompleteScreen,
parentNavigatorKey: _rootNavigatorKey,
builder: (context, state) => const AuthCompleteScreen(),
),
GoRoute(
path: Routes.verifyEmailScreen,
parentNavigatorKey: _rootNavigatorKey,
builder: (context, state) => const EmailVerifyScreen(),
),
StatefulShellRoute.indexedStack(
parentNavigatorKey: _rootNavigatorKey,
builder: (context, state, navigationShell) => MainHomeScreen(navigationShell: navigationShell),
branches: [
StatefulShellBranch(
navigatorKey: _shellNavigatorKey,
routes: [GoRoute(path: Routes.homeScreen, builder: (context, state) => const HomeScreen())],
),
StatefulShellBranch(
routes: [GoRoute(path: Routes.leagueScreen, builder: (context, state) => const LeagueScreen())],
),
StatefulShellBranch(
routes: [GoRoute(path: Routes.newsScreen, builder: (context, state) => const NewsScreen())],
),
StatefulShellBranch(
routes: [GoRoute(path: Routes.menuScreen, builder: (context, state) => const MenuScreen())],
),
],
),
],
debugLogDiagnostics: true,
);
}
My logout in authCubit:
Future<void> logout() async {
emit(AuthLoading());
await authRepo.logout();
emit(UnAuthenticated());
}
My routes:
class Routes {
static const loginScreen = '/login';
static const forgotPasswordScreen = '/login/forgotPassword';
static const registerScreen = '/register';
static const verifyEmailScreen = '/verifyEmail';
static const authCompleteScreen = '/authComplete';
static const profileScreen = '/profile';
static const appShell = '/app';
static const homeScreen = '$appShell/home';
static const leagueScreen = '$appShell/league';
static const newsScreen = '$appShell/news';
static const menuScreen = '$appShell/menu';
static const settingsScreen = '$appShell/settings';
}