Article

Implementing Authentication and Navigation in Flutter Web using go_router

Last updated 
May 30, 2023
 min read

In today’s digital world, where flutter web navigation and flutter web routing are essential, implementing robust authentication and seamless navigation are crucial aspects of any web application.

When it comes to Flutter Web, developers face unique challenges in setting up authentication and navigation due to the nature of web-based interactions.

Fortunately, there is a powerful package called go_router that simplifies the process and enhances the user experience.

In this article, we will delve into the importance of authentication and navigation in Flutter Web, with a specific focus on flutter web navigation and routing. We will also explore how go_router can be utilized to overcome these challenges effectively.

Authentication in Flutter Web:

Authentication forms the backbone of secure web applications, ensuring that only authorized users can access sensitive information or perform specific actions. Implementing authentication in Flutter Web is of utmost importance as it provides several benefits and plays a crucial role in the overall security and integrity of your application.

Benefits of Implementing Authentication:

  1. Data Protection: By implementing authentication, you can safeguard user data from unauthorized access. It ensures that only authenticated users have access to sensitive information, such as personal details, payment information, or private content.
  1. User Accountability: Authentication allows you to establish user accountability within your application. By verifying user identities, you can track and attribute specific actions or modifications to individual users, enabling better auditing and accountability.
  1. Personalized User Experience: Authenticated users can enjoy a personalized experience within your application. You can tailor content, settings, and features based on user preferences, leading to enhanced user satisfaction and engagement.
  2. Secure Communication: Authentication facilitates secure communication between the client and server by employing encryption and cryptographic protocols. This ensures that sensitive data transmitted over the network remains confidential and protected from interception or tampering.

Importance of Implementing Authentication:

  1. Protecting User Privacy: Authentication is crucial for safeguarding user privacy and preventing unauthorized access to personal information. It establishes trust and confidence among users, encouraging them to interact with your application without concerns about their data being compromised.
  1. Preventing Unauthorized Access: Implementing authentication mechanisms prevents unauthorized users from gaining access to restricted areas or performing actions reserved for authenticated users. This adds an additional layer of security and prevents potential misuse or abuse of your application's functionalities.
  1. Regulatory Compliance: Depending on the nature of your application, you may be required to comply with specific regulations and standards, such as GDPR (General Data Protection Regulation). Implementing authentication helps you meet these compliance requirements, ensuring the protection of user data and avoiding potential legal repercussions.
  1. Protecting Intellectual Property: Authentication is vital for safeguarding proprietary or confidential information within your application. By restricting access to authenticated users, you can protect your intellectual property, trade secrets, or confidential business data from unauthorized disclosure or misuse.
  2. Building User Trust: Authentication enhances user trust in your application. When users feel confident that their data is protected, they are more likely to engage with your application, share sensitive information, and conduct transactions. Building user trust is essential for the success and growth of your application.

By recognizing the benefits and understanding the importance of implementing authentication in Flutter Web, you can ensure the security, privacy, and integrity of your application. 

It enables you to provide a seamless and trusted user experience while protecting sensitive data from unauthorized access. 

Invest the necessary time and effort into implementing robust authentication mechanisms to establish a strong foundation for your Flutter Web application's security and success.

Flutter Web Navigation:

Seamless navigation is vital for creating intuitive and user-friendly web applications. In Flutter Web, navigation plays a crucial role in providing a smooth user experience and ensuring users can effortlessly move between different sections of your application. Let's explore the benefits and importance of implementing effective navigation in your Flutter Web projects.

Benefits of Implementing Navigation:

  1. Enhanced User Experience: Proper navigation enables users to explore and interact with your application seamlessly. It allows them to navigate through different screens or sections without confusion, ensuring a positive user experience and increased user satisfaction.
  1. Improved Discoverability: Clear and intuitive navigation makes it easier for users to find and access specific features or content within your application. By organizing information effectively and providing visible navigation elements, users can quickly discover and navigate to the desired sections.
  1. Simplified Information Hierarchy: Navigation helps establish a logical information hierarchy within your application. By categorizing and structuring content using appropriate navigation elements, users can easily understand the relationships between different sections and navigate accordingly.
  2. Consistency across Platforms: Flutter Web's navigation system, which resembles mobile app navigation, provides consistency for users who are already familiar with Flutter mobile applications. By adopting a similar navigation approach, you ensure a seamless experience for users transitioning between different platforms.

Importance of Implementing Navigation:

  1. User Engagement: Intuitive navigation encourages users to explore your application further, leading to increased engagement and prolonged usage. When users can easily navigate between screens and find relevant content, they are more likely to stay engaged with your application and accomplish their goals.
  1. Goal Achievement: Effective navigation facilitates users in achieving their desired goals within your application. Whether it's making a purchase, accessing information, or performing specific actions, streamlined navigation ensures users can reach their intended destinations efficiently.
  1. Conversion Optimization: Well-designed navigation can significantly impact conversion rates. By guiding users through the conversion funnel and providing clear paths to desired actions (such as making a purchase or signing up), you can optimize the conversion process and improve overall conversion rates.
  2. User Retention: Seamless navigation contributes to user retention by reducing friction and frustration during the browsing experience. When users can easily find what they need and navigate through your application effortlessly, they are more likely to return and continue using your application in the future.

Incorporating effective navigation in your Flutter Web application not only enhances the user experience but also helps achieve business goals, improve conversion rates, and increase user retention. By adopting a user-centric approach and designing a clear and intuitive navigation system, you can provide a seamless browsing experience that keeps users engaged, satisfied, and coming back for more.

Investing time and effort in understanding your users' needs, organizing your content, and implementing well-designed navigation elements will undoubtedly contribute to the success and usability of your Flutter Web application.

Learn How to Build a Complex Navigation Stack with Flutter

What is a Go Router?

Go Router is a powerful Flutter package specifically designed for managing navigation in Flutter Web applications. It offers several benefits over the standard Flutter navigation system, making it an excellent choice for implementing navigation in Flutter Web projects. Developers can take complete advantage of Go Router to create a more insightful navigation experience that is in perfect sync with web standards and thus provides users with a seamless interaction flow.

Why use go_router instead of Flutter Navigation 2.0?

While Flutter Navigation 2.0 provides a solid foundation for navigation, go_router offers additional features and flexibility specifically tailored for Flutter Web. It simplifies the navigation process and improves overall performance, resulting in a smoother user experience. Go Router leverages the browser history API to manage the page stack and back navigation, allowing users to navigate backward through the application history using the browser’s back button or other navigation gestures. This feature ensures consistent behavior and enhances user convenience.

Furthermore, Go Router's architecture supports the concept of declarative routing. Under this framework, developers can describe routes and their complementary widgets in a more organized and sorted way. This leads to improved code readability as well as facilitates convenient maintenance as the growth of the application continues.

Features of Go Router:

  • Easy Setup: Go Router provides a straightforward and intuitive API, making it simple to integrate with your Flutter Web project. The setup process of Flutter Web navigation is fast and efficient, so it takes almost similar time and effort for both a seasoned developer and somebody new. Additionally, the documentation and community support ease the integration process further, thereby rendering solid support for you to get up and running with the lowest possible friction.
  • Deep Linking: Go Router enables deep linking by updating the URL dynamically, allowing users to share specific screens or states of your application. This is specifically beneficial for enhancing user engagement and ensuring that shared links are redirecting users to the pre-planned content. Additionally, deep linking has the ability to increase the chances of discoverability of your app’s features, making it convenient for users to access specific content directly.
  • Nested Routing: With Go Router, you can easily implement nested routing, allowing for complex and hierarchical navigation structures. This is necessary for larger applications where it is extremely critical to maintain a neat and organized route framework. Nested routing greatly enhances user navigation as well as enables better code organization, by allowing developers to group together related routes.
  • Error Handling: Go Router offers built-in error handling mechanisms, making it easier to handle exceptions and provide meaningful error messages to users. The efficient management of errors in your Flutter Web app can enhance user experience and also create a professional outlook. The structure also enables developers to define custom error pages, whilst positively ensuring that users are well-informed and guided properly when they face any issues.

Navigation Concepts in Flutter Web

To utilize Go Router efficiently, it is important to develop an understanding of navigation concepts in Flutter Web. There are two primary approaches to navigation that exist: imperative and declarative.

  • Imperative Navigation: In this approach, developers use programming to dictate the navigation pattern. This leads to complex code structures.
  • Declarative Navigation: Go Router primarily emphasizes a declarative approach, that allows developers to describe the UI as a function of the application state. The result of this approach is a cleaner and more manageable code. By utilizing a declarative style, you can easily manage your routes and also develop an understanding about the relationship between your UI and navigation, thus improving readability and reducing complexity, especially when multiple routes are involved.

Common Routing Patterns with Go Router

The implementation of common routing patterns is extremely critical for creating intuitive navigation flows in your Flutter web applications. Go Router supports various routing techniques:

  • Nested Routes: These routes support the creation of complex UI layouts whilst simultaneously keeping your routing logic well-organized. For instance, you can define parent-child routes, where child routes inherit properties from their parent.
  • Dynamic Routes: These routes allow the management of user-generated content by incorporation of certain parameters in your routes, making them context-aware, thereby enhancing user engagement. For instance, a route for displaying user profiles could look like this:
1final router = GoRouter(
2 routes: <GoRoute>[
3   GoRoute(
4     path: '/',
5     redirect: (_, __) => '/dashboard',
6   ),
7   GoRoute(
8     path: '/login',
9     pageBuilder: (context, state) {
10       return MaterialPage(child: const LoginPage());
11     },
12   ),
13   GoRoute(
14     path: '/:kind(dashboard|settings)',
15     pageBuilder: (context, state) => MaterialPage(
16       child: HomePage(kind: state.pathParameters['kind']!),
17     ),
18     routes: [
19       GoRoute(
20         path: DetailsPage.route,
21         pageBuilder: (context, state) {
22           final id = state.pathParameters['id'];
23           return MaterialPage(
24             child: PlantDetailsPage(id: id),
25           );
26         },
27       ),
28     ],
29   ),
30 ],
31);
32

By becoming proficient in these routing patterns, you amplify not only the user experience but also the SEO potential of your application.

Performance Considerations in Go Router

The most crucial factor to consider for any web application is Performance, and Go Router is designed with this as the fundamental foundation. To ensure optimal performance, consider the following strategies:

  • Optimize Route Definitions: Keep your route definitions compact and steer clear of any unnecessary complications. This helps by limiting the rebuilds, especially during navigation, thereby leading to quicker transitions.
  • Efficient State Management: Make proper use of Flutter’s state management solutions (like Provider or Riverpod) to manage the app state effectively, thereby ensuring that only the essential widgets rebuild when there is a change in the state.
  • Benchmarking: Conduct performance benchmarks to evaluate the effect of your routing structure on load times and responsiveness. Go Router’s effective management of complex navigation scenarios can critically reduce dormancy and also enhance the overall user experience.

Error Handling in Go Router

Along with everything else that impacts performance, efficient error handling is mandatory for a sturdy routing solution. Go Router offers strategies to manage errors effectively:

  • Fallback Routes: Execute fallback routes to manage scenarios where a user navigates to a nonexistent route. This makes sure that users are effectively redirected to a friendly error page rather than them landing at a blank screen.
  • Error Pages: Tailor error pages to promptly provide users with helpful information at the correct time about what went wrong and how to navigate back. For example:
1final router = GoRouter(
2 errorBuilder: (context, state) {
3   return Center(
4         child: Text(state.error?.message ?? 'Unknown error'),
5   );
6 },
7 errorPageBuilder: (context, state) {
8   return MaterialPage(
9     child: Scaffold(
10       body: Center(
11         child: Text(state.error?.message ?? 'Unknown error'),
12       ),
13     ),
14   );
15 },
16);
17
  • Capturing Errors: The implementation of error-capturing mechanisms is essential to handle specific errors, such as "no GoRouter found in context." This dynamic approach ensures that users remain engaged, despite any issues arising.

Here’s How You Can Implement Authentication and Navigation in Flutter Web using go_router

Also read: Creating Augmented Reality App with Flutter

Setting Up the Project:

Create a flutter project
  • Create a new Flutter project by running the following command or from Android Studio
flutter create my_app
Add dependencies
  • Add the following dependencies to the pubspec.yaml with the latest version.
1dependencies:
2 go_router: ^7.0.1
3 hive: ^2.2.3
4 hive_flutter: ^1.1.0
5 dev_dependencies:
6 build_runner: ^2.4.2
7 hive_generator: ^2.0.0

Here, the hive is used to store local data. You can use shared_preferences or any other local data storage package instead of the hive.

Creating a Common Service:

Create a common service to handle authentication-related logic, such as user authentication, session management, and secure storage. 

This service will serve as the foundation for implementing authentication in your Flutter Web application.

  • Create a services folder inside the lib folder and create the following file.
  • You can place other common service files inside this folder.
app_service.dart
  • Create a model's folder inside the lib folder and create the following file.
  • The UserData model is helpful for saving data in local storage.
user_data.dart
  • Run the following command to generate the Hive adapter class.
1flutter pub run build_runner build --delete-conflicting-outputs

This command will generate user_data.g.dart at the same location as user_data.dart

Setting Up Navigation:

Initialize go_router in your application and define the initial route.
You can set up a default route and handle the navigation based on the user's authentication status.

  • Create a folder called routing inside the lib folder and create the following two files.
  • GoRoute is used to create each route. If you want to make sub-routes, then those pages will go under the routes array of a GoRoute.
router.dart
1import 'package:flutter/material.dart';
2import 'package:go_router/go_router.dart';
3
4import '../pages/home_page.dart';
5import '../pages/login_page.dart';
6import '../services/app_service.dart';
7
8part 'redirection.dart';
9
10final router = GoRouter(
11 redirect: _redirect,
12 debugLogDiagnostics: true,
13 refreshListenable: AppService.instance,
14 navigatorKey: AppService.instance.navigatorKey,
15 routes: <GoRoute>[
16   GoRoute(
17     path: '/',
18     redirect: (_, __) => HomePage.route,
19   ),
20   GoRoute(
21     path: LoginPage.route,
22     pageBuilder: (context, state) => const MaterialPage(child: LoginPage()),
23   ),
24   GoRoute(
25     path: HomePage.route,
26     pageBuilder: (context, state) => const MaterialPage(child: HomePage()),
27   ),
28 ],
29);

Redirection:

Redirect users based on their authentication status. If a user is not authenticated, redirect them to the login page. Otherwise, navigate them to the home page or any other authorized sections.

  • _redirect method is useful for redirecting the user to a proper route. For example, if a user is logged in to the web page and types the URL of login, then it should go to the home URL automatically. This could be done by the following.
redirection.dart
1part of 'router.dart';
2
3String? _redirect(BuildContext context, GoRouterState state) {
4 final isLoggedIn = AppService.instance.isLoggedIn;
5 final isLoginRoute = state.matchedLocation == LoginPage.route;
6
7 if (!isLoggedIn && !isLoginRoute) {
8   return LoginPage.route;
9 } else if (isLoggedIn && isLoginRoute) {
10   return HomePage.route;
11 }
12 return null;
13}

Setup Routing:

Define routes for different screens and components of your application.
With go_router, you can easily map routes to specific pages or widgets.

  • Edit your main.dart to setup the router using the GoRouter.
main.dart
1import 'package:flutter/material.dart';
2import 'package:flutter_web_plugins/url_strategy.dart';
3import 'package:hive_flutter/hive_flutter.dart';
4
5import 'models/user_data.dart';
6import 'routing/router.dart';
7import 'services/app_service.dart';
8
9void main() async {
10 WidgetsFlutterBinding.ensureInitialized();
11 await Hive.initFlutter();
12 Hive.registerAdapter(UserDataAdapter());
13 await Hive.openBox('App Service Box');
14 runApp(const MyApp());
15}
16
17class MyApp extends StatefulWidget {
18 const MyApp({super.key});
19
20 @override
21 State<MyApp> createState() => _MyAppState();
22}
23
24class _MyAppState extends State<MyApp> {
25 @override
26 void initState() {
27   super.initState();
28   usePathUrlStrategy();
29   AppService.instance.initialize();
30 }
31
32 @override
33 Widget build(BuildContext context) {
34   return MaterialApp.router(
35     title: 'Web Authentication',
36     debugShowCheckedModeBanner: false,
37     routerDelegate: router.routerDelegate,
38     routeInformationParser: router.routeInformationParser,
39     routeInformationProvider: router.routeInformationProvider,
40   );
41 }
42}
  • Here we use MaterialApp.router to implement Navigation 2.0.
  • usePathUrlStrategy is used to remove # from the URL.

Design pages:

Create the necessary pages and widgets for your application.
Each page should correspond to a specific route defined in the go_router configuration and provide the desired functionality.
Design your pages with user-friendly interfaces, intuitive navigation elements, and responsive layouts to ensure a pleasant user experience across various devices.

  • Create a page folder inside lib and create the following files.
  • Login page design with an email and a password field.
login_page.dart
1import 'package:flutter/material.dart';
2import 'package:go_router/go_router.dart';
3import 'package:web_auth_demo/models/user_data.dart';
4import 'package:web_auth_demo/services/app_service.dart';
5
6import 'home_page.dart';
7
8class LoginPage extends StatefulWidget {
9 static const route = '/login';
10
11 const LoginPage({Key? key}) : super(key: key);
12
13 @override
14 State<LoginPage> createState() => _LoginPageState();
15}
16
17class _LoginPageState extends State<LoginPage> {
18 final _emailCtrl = TextEditingController();
19 final _passwordCtrl = TextEditingController();
20
21 @override
22 Widget build(BuildContext context) {
23   return Scaffold(
24     body: ListView(
25       padding: const EdgeInsets.all(16),
26       children: [
27         const Text(
28           'Login to your account',
29           style: TextStyle(
30             fontSize: 16,
31             fontWeight: FontWeight.w600,
32           ),
33         ),
34         const SizedBox(height: 32),
35         TextFormField(
36           controller: _emailCtrl,
37         ),
38         const SizedBox(height: 16),
39         TextFormField(
40           controller: _passwordCtrl,
41           obscureText: true,
42         ),
43         const SizedBox(height: 20),
44         ElevatedButton(
45           onPressed: () {
46             AppService.instance.setUserData(UserData(
47               id: DateTime.now().millisecondsSinceEpoch.toString(),
48               email: _emailCtrl.text,
49             ));
50             context.go(HomePage.route);
51           },
52           child: const Text('Login'),
53         )
54       ],
55     ),
56   );
57 }
58}
home_page.dart
1import 'package:flutter/material.dart';
2import 'package:go_router/go_router.dart';
3
4import '../pages/login_page.dart';
5import '../services/app_service.dart';
6
7class HomePage extends StatefulWidget {
8 static const route = '/home';
9
10 const HomePage({Key? key}) : super(key: key);
11
12 @override
13 State<HomePage> createState() => _HomePageState();
14}
15
16class _HomePageState extends State<HomePage> {
17 @override
18 Widget build(BuildContext context) {
19   return Scaffold(
20     appBar: AppBar(
21       title: const Text('Home page'),
22       actions: [
23         IconButton(
24           onPressed: () async {
25             await AppService.instance.terminate();
26             if (mounted) context.go(LoginPage.route);
27           },
28           icon: const Icon(Icons.logout),
29         )
30       ],
31     ),
32     body: Center(
33       child: Text('Login to ${AppService.instance.currentUser!.email}'),
34     ),
35   );
36 }
37}

Explore a comparison between the performance of an app built with Native Android and Flutter.

Comparing Go Router with Other Routing Solutions

While Go Router is a powerful and reliable option for Flutter Web navigation, it’s important to compare it with other routing solutions to determine the best option for your project.

  • Go Router: This is innately known for its simplicity and adaptability. Go Router enables developers to create routes declaratively. It drives excellent performance in handling nested and dynamic routes, thereby making it ideal for applications that require complex navigation frameworks.
  • Auto Route: Auto Route offers comprehensive code generation features, that prove to be extremely beneficial for projects with various routes. However, it may introduce additional complications in comparison to Go Router’s straightforward approach and setup.
  • Fluro: Fluro is another reliable alternative that distinctively focuses on a more traditional routing approach, thus providing more control over route handling. Even though it’s powerful, it may need more boilerplate code. Also, unlike other approaches, it can be less insightful for new developers.

While making a choice for a routing solution, consider your project’s specific needs, the complexity of your navigation, and your team's familiarity and comfort with the tools. After following a thorough approach of evaluation of all these factors, you can select the most efficient and fitting routing solution for your Flutter Web application.

Conclusion:

Implementing authentication and navigation in Flutter Web is vital for creating secure and user-friendly web applications. 

The go_router package offers a powerful solution for managing navigation, providing a seamless browsing experience for users. By leveraging go_router, developers can simplify the navigation setup process, handle authentication efficiently, and enhance the overall user experience.

By following the steps outlined in this article, you can easily set up go_router in your Flutter Web project, add necessary dependencies, create a common service for authentication logic, define routes, and design pages that provide a cohesive and intuitive user experience. For any assistance with Flutter app development, connect with our team of skilled Flutter developers today. They will provide expert guidance and deliver top-notch solutions tailored to your needs.

If you enjoyed this blog, you might also be interested in our post on optimizing paginated list fetching in Flutter using the generic BLoC pattern.

Authors

Nayan Babariya

Software Engineer - II
Senior Flutter Engineer specializing in cross-platform mobile application development using the Flutter framework. I excel at building high-quality, scalable apps and digital solutions.

Tags

No items found.

Have a project in mind?

Read