Firebase Authentication and keeping users logged in with Provider in Flutter.
By: Raajeev Chandran
Tags: State Management, Flutter, Authentication, Provider, Firebase

Incorporating firebase authentication into a flutter application can now be done in no-time, but the conventional way of doing so doesn’t turn out to be user-friendly in any manner. We just can’t expect our users to be keyboard-warriors and make them tolerant of signing in every-time they get their hands on our application.

So, let’s fix this user experience clutter by keeping the user logged in by managing the state with the Provider package until the user smashes that “Sign Out” button.

We are just going be managing the state of our application with the Provider and orchestrate the execution flow based on whether the user is “Signed in” or not.

ARCHITECTURE OF THE APPLICATION IN THIS ARTICLE.

Create a flutter project on your machine. (I’m skipping this part of elucidating steps as I don't wanna make your eyelids weary of reading :) ) Create a firebase project for Flutter. If you have done it already, then I would suggest skipping to the plot of the article. Novices can check out this webpage to integrate Firebase into your flutter application.

What is Provider and why is it worthwhile to use?

On the bottom line, we are about to watch over a value (in this case, logged in or not) and take requisite actions. So typically we are gonna be listening to a value and watch over its changes to manipulate the workflow of our application. And this is where the Provider comes into play, by the time you read this article, some might have figured out what’s really powering this Provider under the hood. The Provider is just an incarnation of the InheritedWidget and ChangeNotifier which lets you expose/create/listen/dispose a value. So deciphers the offical documentation.

Let’s now deep dive into the to-dos.

Open the pubspec.yaml file in your Flutter project and add the following packages. (provider ,firebase_auth , firebase_core)

We’ll kick-start this application by first finishing up with our Provider. Create an authentication.dart file in the lib directory.

Import the dependencies. Create an AuthenticationProvider class with a firebaseAuth instance.

import 'package:firebase_auth/firebase_auth.dart'; class AuthenticationProvider{ final FirebaseAuth firebaseAuth;

// FirebaseAuth instance AuthenticationProvider(this.firebaseAuth);

//Constructor to initialize the Firebase Auth instance. }

We’ll use a Stream to continuously listen to the Authentication State(logged in or not).

Stream<User> get authStateChanges => firebaseAuth.idTokenChanges();

Let’s quickly add the Sign-Up, Sign in, and Sign out methods.

We have now finished setting up our Authentication Provider. Let’s now fit this provider into our main.dart file.

In the main.dart file, import the following dependencies.

import 'package:flutter/material.dart';

import 'package:firebase_core/firebase_core.dart';

import 'package:provider/provider.dart';

import 'package:firebase_auth/firebase_auth.dart';

2.We are about to make our main method async in order to make our Firebase Authentication completely error-free and give it a few nano-seconds to gear up.

Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); runApp(MyApp()); //MyApp is our root widget. }

POINTS TO PONDER WHEN USING PROVIDER Providers are strictly scoped which means that they turn out to be erroneous when not defined in the right place. Always ensure that you initialize your Providers in the root widget (top of the widget tree to be more precise) so that they remain accessible throughout the nested widget tree and nested navigation routes. In case you run into a scenario where you don’t want your Provider to be initialized in the Root widget, remember that any attempts to accessing the Provider which you defined in some other route makes that Provider to be inaccessible to its ancestor widgets/Root Widget in the Widget tree. Hence that Provider will only be accessible by its child/descendant widgets.

3. Creating our Root Widget (MyApp). As the Providers need to rest on the top of the Widget tree, we will make the MaterialApp widget as the child of the MultiProvider widget to initialize our Providers in the build method.

3.a. Initialize the AuthenticationProvider using Provider()

3.b. Use StreamProvider() to read the value from the authState method in the AuthenticationProvider.

4. Now let’s add another class Authenticate to decide which route the application has to take based on the authState.

Complete main.dart file.

Time to build our HomePage and LogInPage routes. (Make sure you import them in the main.dart file).

login_page.dart

home_page.dart

And that’s a wrap!

This way, we have managed the state with the Provider to keep our users logged in. Hope the article was engaging enough. Still, stuck somewhere? Feel free to check out the GitHub repository.