Seamless Auto-Redirect Authentication with Firebase, Riverpod Generator and GoRouter

Omasuaku
3 min readSep 8, 2024

In any modern app, managing authentication is essential. However, it’s not just about verifying the user’s identity; efficiently directing users to the right page based on their authentication state is crucial for a seamless flow. Imagine a user opening your app: if they are logged in, they should be taken directly to the home page. If not, they should be redirected to the login or signup page. This auto-redirection ensures that users are always taken to the right place without unnecessary steps, improving navigation and reducing confusion.

1. First, let’s listen to the current user with firebase

@Riverpod(keepAlive: true)
class UserNotifier extends _$UserNotifier {
@override
Stream<User?> build() => FirebaseAuth.instance.authStateChanges();
}

With this provider, we can monitor the authentication state at any time. It taps into Firebase’s authStateChanges() stream, which emits the current user state whenever the authentication status changes (e.g., when a user logs in, logs out).

2. Create AsyncValueNotifier

By default, GoRouter’s refreshListenable does not support AsyncValue directly, as it only works with ChangeNotifier or other Listenable types. This poses a challenge when using Riverpod’s AsyncValue to manage the authentication state, but there’s a simple solution: creating a ChangeNotifier that wraps the AsyncValue so that GoRouter can refresh whenever the authentication state changes.

class AsyncValueNotifier<T> extends ChangeNotifier {
AsyncValueNotifier(this._asyncValue);

AsyncValue<T> _asyncValue;

AsyncValue<T> get asyncValue => _asyncValue;

void update(AsyncValue<T> newValue) {
if (newValue != _asyncValue) {
_asyncValue = newValue;
notifyListeners();
}
}
}

3. Create Provider for the ChangeNotifier

To ensure that GoRouter stays in sync with the current user’s authentication state, we need to create a Provider that supplies and updates the ChangeNotifier we just created. This provider will be responsible for providing the AsyncValueNotifier to GoRouter, which in turn will trigger automatic redirection when the user’s state changes.

@Riverpod(keepAlive: true)
Raw<AsyncValueNotifier<User?>> currentUserNotifier(CurrentUserNotifierRef ref) {
final asyncValue = ref.watch(userNotifierProvider);
final notifier = AsyncValueNotifier<User?>(asyncValue);

ref.listen<AsyncValue<User?>>(userNotifierProvider, (previous, next) {
notifier.update(next);
});

return notifier;
}

4. Create the router

Now that we have set up the AsyncValueNotifier and the provider, we can go ahead and integrate GoRouter with Riverpod. The key step here is to make GoRouter aware of changes in the user’s authentication state by watching the currentUserNotifier we created. This way, GoRouter will automatically handle navigation updates whenever the authentication state changes.

part 'router.g.dart';

final routerKey = GlobalKey<NavigatorState>();

@Riverpod(keepAlive: true)
GoRouter router(RouterRef ref) {
final user = ref.watch(currentUserNotifierProvider);


return GoRouter(
navigatorKey: routerKey,
refreshListenable: user,
initialLocation: AuthRoute().location,
routes: $appRoutes,
redirect: (context, state) {
final isLogged = user.asyncValue.value != null;

if (state.uri.path == AuthRoute().location && isLogged) return HomeRoute().location;

if (!isLogged) return AuthRoute().location;

return null;
},
);
}

5. Create MaterialApp

class MyApp extends HookConsumerWidget {
const MyApp({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
final router = ref.watch(routerProvider);

return MaterialApp.router(
debugShowCheckedModeBanner: false,
routeInformationParser: router.routeInformationParser,
routeInformationProvider: router.routeInformationProvider,
routerDelegate: router.routerDelegate,
);
}
}

This setup ensures that your app always shows the correct screen based on the user’s authentication state, with GoRouter automatically handling redirection when needed.

6. Conclusion

Implementing seamless auto-redirect authentication in a Flutter app can significantly improve the user experience by ensuring that users are always routed to the appropriate page based on their authentication status. By leveraging Firebase for authentication, Riverpod for state management, and GoRouter for routing, we’ve created a flexible, scalable solution that can dynamically adjust the navigation flow as the authentication state changes.

With this approach, you can ensure that your app handles authentication efficiently, while maintaining a clean and responsive navigation structure. Whether you’re working on a small app or a large project, this setup will help keep your users’ sessions secure and their experience smooth.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Omasuaku
Omasuaku

Written by Omasuaku

Programmer from Africa. I’m here just to say a hello to the world.

No responses yet

Write a response

Recommended from Medium

Lists

See more recommendations