Quick Start
import { Steps } from ‘@astrojs/starlight/components’;
This guide will help you create your first guard and protect a route in just a few minutes.
Prerequisites
Section titled “Prerequisites”- Flutter project with Go Router already set up
- Go Router Guards installed
5-Minute Setup
Section titled “5-Minute Setup”-
Create Your First Guard
Create a simple authentication guard:
import 'dart:async';import 'package:flutter/material.dart';import 'package:go_router_guards/go_router_guards.dart';class AuthGuard extends GoRouterGuard {@overrideFutureOr<void> onGoRouterNavigation(NavigationResolver resolver,BuildContext context,GoRouterState state,) async {// Simulate checking authenticationfinal isAuthenticated = await _checkAuth();if (isAuthenticated) {resolver.next(); // Allow navigation} else {resolver.redirect('/login'); // Redirect to login}}Future<bool> _checkAuth() async {// Your authentication logic herereturn false; // For demo purposes}} -
Protect a Type-Safe Route
Use the
GuardedRoute
mixin to protect a route:import 'package:go_router/go_router.dart';import 'package:go_router_guards/go_router_guards.dart';@TypedGoRoute<ProfileRoute>(path: '/profile')class ProfileRoute extends GoRouteData with GuardedRoute {@overrideRouteGuard get guards => AuthGuard();@overrideWidget build(BuildContext context, GoRouterState state) {return const ProfileScreen();}} -
Set Up Your Router
Configure your Go Router with the protected routes:
final router = GoRouter(routes: [// Your login route (unprotected)GoRoute(path: '/login',builder: (context, state) => const LoginScreen(),),// Type-safe protected route...ProfileRoute().routes,],); -
Test the Protection
Run your app and try to navigate to
/profile
. You should be redirected to/login
!
Alternative: Traditional Routes
Section titled “Alternative: Traditional Routes”If you prefer traditional Go Router syntax:
final router = GoRouter( routes: [ GoRoute( path: '/login', builder: (context, state) => const LoginScreen(), ), GoRoute( path: '/profile', builder: (context, state) => const ProfileScreen(), redirect: RouteGuardUtils.createGuardRedirect(AuthGuard()), ), ],);
What Just Happened?
Section titled “What Just Happened?”- Created a Guard:
AuthGuard
checks authentication and redirects unauthenticated users - Protected a Route:
ProfileRoute
usesGuardedRoute
mixin to apply the guard - Handled Navigation: The guard automatically intercepts navigation attempts
Next Steps
Section titled “Next Steps”Now that you have basic protection working, explore these features:
Combine Multiple Guards
Section titled “Combine Multiple Guards”class AdminRoute extends GoRouteData with GuardedRoute { @override RouteGuard get guards => Guards.all([ AuthGuard(), RoleGuard(['admin']), ]);}
Create Role-Based Guards
Section titled “Create Role-Based Guards”class RoleGuard extends GoRouterGuard { const RoleGuard(this.requiredRoles);
final List<String> requiredRoles;
@override FutureOr<void> onGoRouterNavigation( NavigationResolver resolver, BuildContext context, GoRouterState state, ) async { final userRoles = await getUserRoles(); final hasRequiredRole = requiredRoles.any(userRoles.contains);
if (hasRequiredRole) { resolver.next(); } else { resolver.redirect('/unauthorized'); } }}
Add Router-Level Protection
Section titled “Add Router-Level Protection”final router = GoRouter( routes: $appRoutes, // Protect all routes except login redirect: RouteGuardUtils.createGuardRedirect( ConditionalGuard( guard: AuthGuard(), excludedPaths: ['/login', '/register'], ), ),);
Common Patterns
Section titled “Common Patterns”Loading States
Section titled “Loading States”class AuthGuard extends GoRouterGuard { @override FutureOr<void> onGoRouterNavigation( NavigationResolver resolver, BuildContext context, GoRouterState state, ) async { // Show loading indicator showDialog( context: context, builder: (_) => const CircularProgressIndicator(), );
try { final isAuthenticated = await _checkAuth(); Navigator.of(context).pop(); // Hide loading
if (isAuthenticated) { resolver.next(); } else { resolver.redirect('/login'); } } catch (error) { Navigator.of(context).pop(); // Hide loading resolver.redirect('/error'); } }}
Conditional Logic
Section titled “Conditional Logic”class SubscriptionGuard extends GoRouterGuard { @override FutureOr<void> onGoRouterNavigation( NavigationResolver resolver, BuildContext context, GoRouterState state, ) async { final user = await getCurrentUser();
if (user.hasActiveSubscription) { resolver.next(); } else if (user.isTrialExpired) { resolver.redirect('/subscription-required'); } else { resolver.redirect('/trial-warning'); } }}
Debugging Tips
Section titled “Debugging Tips”Enable Guard Logging
Section titled “Enable Guard Logging”class AuthGuard extends GoRouterGuard { @override FutureOr<void> onGoRouterNavigation( NavigationResolver resolver, BuildContext context, GoRouterState state, ) async { print('AuthGuard: Checking route ${state.uri}');
final isAuthenticated = await _checkAuth(); print('AuthGuard: User authenticated: $isAuthenticated');
if (isAuthenticated) { print('AuthGuard: Allowing navigation'); resolver.next(); } else { print('AuthGuard: Redirecting to login'); resolver.redirect('/login'); } }}
Test Your Guards
Section titled “Test Your Guards”void main() { testWidgets('AuthGuard redirects unauthenticated users', (tester) async { final guard = AuthGuard(); final context = MockBuildContext(); final state = MockGoRouterState();
final result = await guard.executeWithResolver(context, state);
expect(result.continueNavigation, false); expect(result.redirectPath, '/login'); });}
Need Help?
Section titled “Need Help?”- 📖 Read the detailed Guides
- 🔍 Check out Examples
- 💬 Ask questions in GitHub Discussions
- 🐛 Report issues on GitHub
You’re now ready to build sophisticated navigation protection! 🎉