<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Justice Nwogu - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Justice Nwogu - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Fri, 15 May 2026 17:23:07 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/jaycodes1/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Secure User Authentication Flow in Flutter with Firebase and Bloc State Management ]]>
                </title>
                <description>
                    <![CDATA[ User authentication is critical to mobile app development. It helps make sure that only authorized users can access sensitive information and perform actions within an application. In this tutorial, we will explore how to build secure user authentica... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/user-authentication-flow-in-flutter-with-firebase-and-bloc/</link>
                <guid isPermaLink="false">66be1f69a1b2d9ba40be180e</guid>
                
                    <category>
                        <![CDATA[ BLoC ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Firebase ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ State Management  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Justice Nwogu ]]>
                </dc:creator>
                <pubDate>Tue, 21 Nov 2023 15:21:20 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/11/Group-1--3-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>User authentication is critical to mobile app development. It helps make sure that only authorized users can access sensitive information and perform actions within an application.</p>
<p>In this tutorial, we will explore how to build secure user authentication in Flutter using Firebase for authentication and the Bloc state management pattern for handling application state. By the end, you'll have a solid understanding of how to integrate Firebase authentication and implement a secure login and sign-up process using Bloc.</p>
<h3 id="heading-prerequisites">Prerequisites:</h3>
<p>To get the most out of this tutorial, you should have the following:</p>
<ul>
<li>A good understanding of Flutter and Dart</li>
<li>A Firebase account: Create a Firebase account if you don't have one. You can set up a Firebase project through the <a target="_blank" href="https://console.firebase.google.com/">Firebase Console</a>.</li>
</ul>
<h2 id="heading-how-firebase-authentication-works"><strong>How Firebase Authentication Works</strong></h2>
<p>Firebase Authentication is a powerful service that simplifies the process of authenticating users in your app. It supports various authentication methods, including email/password, social media, and more.</p>
<p>One of the key advantages of Firebase Authentication is its built-in security features, such as secure storage of user credentials and encryption of sensitive data.</p>
<h2 id="heading-flowchart-description"><strong>FlowChart Description</strong></h2>
<p>Let's visualize the flow of actions using a flowchart to understand the concept you are going to learn. Take a look at the diagram below to get a better understanding:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/Flowcharts.png" alt="Image" width="600" height="400" loading="lazy">
<em>Img 1: The flowchart of the app</em></p>
<p>The image above is a flowchart to visualize the flow of the app let's discuss what each parts represents. The rounded rectangles represent the starting and ending points of the flow; the purple rectangles represent the screens; the light blue rectangles represent the processes that take place; and finally, the rhombus represents decision-making.</p>
<ul>
<li>The application starts at the <code>AuthenticationFlowScreen</code>.</li>
<li>The <code>StreamBuilder</code> listens to authentication state changes.</li>
<li>If a user is authenticated, it directs to the <code>HomeScreen</code>; otherwise, it leads to the <code>SignupScreen</code>.</li>
<li><code>AuthenticationBloc</code> manages user authentication events and states.</li>
<li>When the user signs up (<code>SignUpUser</code> event is triggered):</li>
<li>It initiates the authentication loading state (<code>AuthenticationLoadingState</code>).</li>
<li>Calls <code>signUpUser</code> from <code>AuthService</code> for user registration.</li>
<li>If successful, it emits  <code>AuthenticationSuccessState</code> with user data; otherwise, emits <code>AuthenticationFailureState</code>.</li>
<li>When the user initiates the sign-out process (<code>SignOut</code> event is triggered):</li>
<li>It starts the authentication loading state (<code>AuthenticationLoadingState</code>).</li>
<li>Calls <code>signOutUser</code> from <code>AuthService</code> to sign the user out.</li>
<li>If an error occurs during sign-out, it logs the error message.</li>
</ul>
<h2 id="heading-project-setup"><strong>Project Setup</strong></h2>
<p>To get started with Firebase Authentication, you must set up Firebase in your Flutter project.</p>
<p>Follow these steps to add Firebase and bloc to your project:</p>
<h3 id="heading-add-dependencies-to-your-project">Add Dependencies to Your Project</h3>
<p>Open your project in your preferred code editor.</p>
<p>Add the following dependencies to your <code>pubspec.yaml</code> file:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">dependencies:</span>
<span class="hljs-attr">firebase_core:</span> <span class="hljs-string">^2.20.0</span>
<span class="hljs-attr">firebase_auth:</span> <span class="hljs-string">^4.12.0</span>
<span class="hljs-attr">flutter_bloc:</span> <span class="hljs-string">^8.1.3</span>
</code></pre>
<p>Then save the <code>pubspec.yaml</code> file to fetch the dependencies.</p>
<h3 id="heading-configure-firebase">Configure Firebase</h3>
<p>Create a new Firebase project through the Firebase <a target="_blank" href="https://www.freecodecamp.org/news/p/9b9114d1-6fce-4349-a755-fdaa04b2d4ae/console.firebase.google.com">Console</a>. Click on authentication in the project, and follow the provided instructions.</p>
<p>For more information, you can go through the Firebase <a target="_blank" href="https://firebase.google.com/docs/auth">website</a>.</p>
<h3 id="heading-initialize-firebase">Initialize Firebase</h3>
<p>First, open the <code>main.dart</code> file in the <code>lib</code> folder.</p>
<p>Add the following code to the file to initialize Firebase:</p>
<pre><code class="lang-dart">
<span class="hljs-keyword">void</span> main() <span class="hljs-keyword">async</span> {
WidgetsFlutterBinding.ensureInitialized();
<span class="hljs-keyword">await</span> Firebase.initializeApp(
  options: DefaultFirebaseOptions.currentPlatform
);
</code></pre>
<p>The code above shows the code for running the app. There's nothing unusual about this code except that we have added some code to the <code>void main</code> to initialize Firebase.</p>
<h3 id="heading-the-user-model">The User Model</h3>
<p>Before creating the Firebase class to communicate with the Firebase service, let's define a UserModel to represent the user data.</p>
<p>Start by creating a <code>user.dart</code> file in your project's <code>lib</code> directory.</p>
<p>Then add the code below in the file:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserModel</span> </span>{
<span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> id;
<span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> email;
<span class="hljs-keyword">final</span> <span class="hljs-built_in">String?</span> displayName;
UserModel({ <span class="hljs-keyword">this</span>.id, <span class="hljs-keyword">this</span>.email, <span class="hljs-keyword">this</span>.displayName, });
}
</code></pre>
<p>Now that you have set up Firebase and created a user model, you need to create a service class to communicate with Firebase directly.</p>
<h3 id="heading-the-authentication-service">The Authentication Service</h3>
<p> Create a folder called <code>services</code>, create a file in this folder called <code>authentication.dart</code> You can now add this code to the file.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:firebase_auth/firebase_auth.dart'</span>;

<span class="hljs-keyword">import</span> <span class="hljs-string">'../models/user.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthService</span> </span>{
  <span class="hljs-keyword">final</span> FirebaseAuth _firebaseAuth = FirebaseAuth.instance;


  <span class="hljs-comment">/// <span class="markdown">create user</span></span>
  Future&lt;UserModel?&gt; signUpUser(
    <span class="hljs-built_in">String</span> email,
    <span class="hljs-built_in">String</span> password,
  ) <span class="hljs-keyword">async</span> {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">final</span> UserCredential userCredential =
          <span class="hljs-keyword">await</span> _firebaseAuth.createUserWithEmailAndPassword(
        email: email.trim(),
        password: password.trim(),
      );
      <span class="hljs-keyword">final</span> User? firebaseUser = userCredential.user;
      <span class="hljs-keyword">if</span> (firebaseUser != <span class="hljs-keyword">null</span>) {
        <span class="hljs-keyword">return</span> UserModel(
          id: firebaseUser.uid,
          email: firebaseUser.email ?? <span class="hljs-string">''</span>,
          displayName: firebaseUser.displayName ?? <span class="hljs-string">''</span>,
        );
      }
    } <span class="hljs-keyword">on</span> FirebaseAuthException <span class="hljs-keyword">catch</span> (e) {
      <span class="hljs-built_in">print</span>(e.toString());
    }
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
  } 

   <span class="hljs-comment">///<span class="markdown">signOutUser </span></span>
   Future&lt;<span class="hljs-keyword">void</span>&gt; signOutUser() <span class="hljs-keyword">async</span> {
      <span class="hljs-keyword">final</span> User? firebaseUser = FirebaseAuth.instance.currentUser;
    <span class="hljs-keyword">if</span> (firebaseUser != <span class="hljs-keyword">null</span>) {
      <span class="hljs-keyword">await</span> FirebaseAuth.instance.signOut();
    }
  }
  <span class="hljs-comment">// ... (other methods)}</span>
}
</code></pre>
<p>The code snippet above is a method to create a user in the app using Firebase. With this method, the <code>signUpUser</code> method takes two string parameters: <code>email</code> and <code>password</code> respectively. Then you call the Firebase method to create a user using the parameters we added.</p>
<p>Now that you know how to create the signup method, you can also create the login method. The class ultimately portrays the communication between Firebase and the app.</p>
<p>The next part is to connect the service to your state management, which we'll see how to do now.</p>
<h2 id="heading-how-bloc-state-management-works"><strong>How Bloc State Management Works</strong></h2>
<p>Bloc is a popular state management pattern for Flutter that helps manage complex application states predictably and in a testable way. Bloc stands for "<strong>Business Logic Component</strong>" and it divides the business logic and the UI. Bloc will be the bridge between your app and Firebase.</p>
<p>There's an extension for <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=FelixAngelov.bloc">VScode</a> that creates the boilerplate code for Bloc. You can use the extension to speed up the development process.</p>
<h3 id="heading-set-up-firebase-authentication-bloc">Set Up Firebase Authentication Bloc</h3>
<p>Bloc consists of events and states. Let's first create the states and events for the Bloc. Then we'll create a <code>AuthenticationBloc</code> that will handle the logic using the events, states, and service we have created.</p>
<h4 id="heading-the-authenticationstate-class">The <code>AuthenticationState</code> class</h4>
<p>The <code>AuthenticationState</code> class is responsible for the authentication process's different states. As we will see in the code, there are initial, loading, success, and failure states to ensure we know what happens during the authentication process.</p>
<p>First, create an <code>authentication_state.dart</code> file in your project's <code>bloc</code> directory.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">part</span> of <span class="hljs-string">'authentication_bloc.dart'</span>;


<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthenticationState</span> </span>{
  <span class="hljs-keyword">const</span> AuthenticationState();

  <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Object</span>&gt; <span class="hljs-keyword">get</span> props =&gt; [];
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthenticationInitialState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AuthenticationState</span> </span>{}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthenticationLoadingState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AuthenticationState</span> </span>{
 <span class="hljs-keyword">final</span> <span class="hljs-built_in">bool</span> isLoading;

  AuthenticationLoadingState({<span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.isLoading});
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthenticationSuccessState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AuthenticationState</span> </span>{
  <span class="hljs-keyword">final</span> UserModel user;

  <span class="hljs-keyword">const</span> AuthenticationSuccessState(<span class="hljs-keyword">this</span>.user);
  <span class="hljs-meta">@override</span>
  <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Object</span>&gt; <span class="hljs-keyword">get</span> props =&gt; [user];
}
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthenticationFailureState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AuthenticationState</span> </span>{
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String</span> errorMessage;

  <span class="hljs-keyword">const</span> AuthenticationFailureState(<span class="hljs-keyword">this</span>.errorMessage);

  <span class="hljs-meta">@override</span>
  <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Object</span>&gt; <span class="hljs-keyword">get</span> props =&gt; [errorMessage];
}
</code></pre>
<p>Let's break down the code:</p>
<p><code>AuthenticationState</code> abstract class:</p>
<ul>
<li><code>AuthenticationState</code> is the base class for different states where the authentication process can be at any time.</li>
<li>It contains a method <code>props</code> that returns a list of objects. This method is used for equality checking when comparing instances of this class.</li>
</ul>
<p><code>AuthenticationInitialState</code> class:</p>
<ul>
<li><code>AuthenticationInitialState</code> represents the initial state of the authentication process.</li>
</ul>
<p><code>AuthenticationLoadingState</code> class:</p>
<ul>
<li><code>AuthenticationLoadingState</code> represents a state where the authentication process is in progress, and the UI might show a loading indicator.</li>
<li>It takes a boolean parameter, <code>isLoading</code>, to indicate whether or not the authentication process is currently loading.</li>
</ul>
<p><code>AuthenticationSuccessState</code> class:</p>
<ul>
<li><code>AuthenticationSuccessState</code> represents a state where the authentication process has been completed.</li>
<li>It includes a user property of type UserModel representing the authenticated user.</li>
</ul>
<p><code>AuthenticationFailureState</code> class:</p>
<ul>
<li><code>AuthenticationFailureState</code>  represents a state where the authentication process has failed.</li>
<li>It includes an <code>error message</code> property containing information about the failure.</li>
</ul>
<h4 id="heading-the-authenticationevent-class">The <code>AuthenticationEvent</code> class</h4>
<p>The <code>AuthenticationEvent</code> is responsible for the events the <code>AuthenticationBloc</code> will perform. In this case, it is the sign-in event. You can write the other events, like sign-up and sign-out, here.</p>
<p>Create a <code>authentication_Event.dart</code> file in your project's <code>bloc</code> directory.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">part</span> of <span class="hljs-string">'authentication_bloc.dart'</span>;



<span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthenticationEvent</span> </span>{
  <span class="hljs-keyword">const</span> AuthenticationEvent();

  <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Object</span>&gt; <span class="hljs-keyword">get</span> props =&gt; [];

}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SignUpUser</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AuthenticationEvent</span> </span>{
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String</span> email;
  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String</span> password;

  <span class="hljs-keyword">const</span> SignUpUser(<span class="hljs-keyword">this</span>.email, <span class="hljs-keyword">this</span>.password);

  <span class="hljs-meta">@override</span>
  <span class="hljs-built_in">List</span>&lt;<span class="hljs-built_in">Object</span>&gt; <span class="hljs-keyword">get</span> props =&gt; [email, password];
}


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SignOut</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AuthenticationEvent</span> </span>{}
</code></pre>
<p>The <code>AuthenticationEvent</code> class is similar to <code>AuthenticationState</code>. Let's look at the code to see what it's doing:</p>
<p><code>AuthenticationEvent</code> abstract class:</p>
<ul>
<li>This is the base class for different events that trigger authentication state changes.</li>
</ul>
<p><code>SignUpUser</code> class:</p>
<ul>
<li>This class represents an event where a user is attempting to sign up.</li>
<li>It takes two parameters, <code>email</code> and <code>password</code>, representing the credentials the user is using to sign up.</li>
<li>This class's instances will signal the <code>Bloc</code> that a user is trying to sign up, and the <code>Bloc</code> can respond by initiating the sign-up process and transitioning the authentication state accordingly.</li>
</ul>
<p><code>SignOut</code> class:</p>
<ul>
<li>This class's instances will signal the <code>Bloc</code> that a user is trying to sign out. The <code>bloc</code> can respond by initiating the sign-out process and updating the authentication state accordingly.</li>
</ul>
<h4 id="heading-the-authenticationbloc-class">The <code>AuthenticationBloc</code> class</h4>
<p>The <code>AuthenticationBloc</code> will handle the overall authentication state, from what happens when a user clicks a button to what shows on the screen. It also interacts with the Firebase service we created directly.</p>
<p>First, create a file called <code>authentication_bloc.dart</code> in your project's <code>bloc</code> directory.</p>
<p>Add the following code to define the <code>AuthenticationBloc</code> class:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:bloc/bloc.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:meta/meta.dart'</span>;

<span class="hljs-keyword">import</span> <span class="hljs-string">'../models/user.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'../services/authentication.dart'</span>;

<span class="hljs-keyword">part</span> <span class="hljs-string">'authentication_event.dart'</span>;
<span class="hljs-keyword">part</span> <span class="hljs-string">'authentication_state.dart'</span>;



<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthenticationBloc</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Bloc</span>&lt;<span class="hljs-title">AuthenticationEvent</span>, <span class="hljs-title">AuthenticationState</span>&gt; </span>{
  <span class="hljs-keyword">final</span> AuthService authService = AuthService();

  AuthenticationBloc() : <span class="hljs-keyword">super</span>(AuthenticationInitialState()) {
    <span class="hljs-keyword">on</span>&lt;AuthenticationEvent&gt;((event, emit) {});

    <span class="hljs-keyword">on</span>&lt;SignUpUser&gt;((event, emit) <span class="hljs-keyword">async</span> {
      emit(AuthenticationLoadingState(isLoading: <span class="hljs-keyword">true</span>));
      <span class="hljs-keyword">try</span> {
          <span class="hljs-keyword">final</span> UserModel? user =
          <span class="hljs-keyword">await</span> authService.signUpUser(event.email, event.password);
      <span class="hljs-keyword">if</span> (user != <span class="hljs-keyword">null</span>) {
        emit(AuthenticationSuccessState(user));

      } <span class="hljs-keyword">else</span> {
        emit(<span class="hljs-keyword">const</span> AuthenticationFailureState(<span class="hljs-string">'create user failed'</span>));
      }
      } <span class="hljs-keyword">catch</span> (e) {
        <span class="hljs-built_in">print</span>(e.toString());
      }
     emit(AuthenticationLoadingState(isLoading: <span class="hljs-keyword">false</span>));
    });

     <span class="hljs-keyword">on</span>&lt;SignOut&gt;((event, emit) <span class="hljs-keyword">async</span> {
      emit(AuthenticationLoadingState(isLoading: <span class="hljs-keyword">true</span>));
      <span class="hljs-keyword">try</span> {
        authService.signOutUser();
      } <span class="hljs-keyword">catch</span> (e) {
        <span class="hljs-built_in">print</span>(<span class="hljs-string">'error'</span>);
        <span class="hljs-built_in">print</span>(e.toString());
      } 
       emit(AuthenticationLoadingState(isLoading: <span class="hljs-keyword">false</span>));
     });
}
}
</code></pre>
<p>In this code snippet, we have created an instance of the <code>AuthService</code> class, which handles user authentication operations, such as signing up and signing out.</p>
<p><code>on&lt;SignUpUser&gt;((event, emit) async { ... }</code> defines a handler for the <code>SignUpUser</code> event. When this event is triggered, the <code>bloc</code> goes through the following steps:</p>
<ul>
<li>It emits an  <code>AuthenticationLoadingState</code> to indicate that the authentication process is in progress.</li>
<li>It calls for the <code>signUpUser</code> method of the  <code>authService</code> to attempt to create a user account with the provided email and password.</li>
<li>If the user account creation is successful (that is, the user is not null), it emits an  <code>AuthenticationSuccessState</code> with the user data.</li>
<li>If the user account creation fails, it emits an <code>AuthenticationFailureState</code> with an error message and logs the error.</li>
<li>Regardless of success or failure, it emits another <code>AuthenticationLoadingState</code> to signal the end of the authentication process.</li>
</ul>
<p><code>on&lt;SignOut&gt;((event, emit) async { ... }</code> defines a handler for the <code>SignOut</code>  event. When this event is triggered, the <code>bloc</code> goes through the following steps:</p>
<ul>
<li>It emits an <code>AuthenticationLoadingState</code> to indicate that the sign-out process is in progress.</li>
<li>It calls the <code>signOutUser</code> method of the <code>authService</code> to sign the user out.</li>
<li>If any errors occur during the sign-out process, it logs the error.</li>
<li>It emits another <code>AuthenticationLoadingState</code> to signal the end of the sign-out process.</li>
</ul>
<p>The <code>AuthenticationBloc</code> manages the state of the authentication process, including loading, success, and failure states, based on the events triggered by user actions. The <code>authService</code> is responsible for carrying out the actual authentication operations.  </p>
<p>With the Bloc set up, we can implement the authentication flow using Bloc.</p>
<h2 id="heading-how-to-implement-the-authentication-flow-with-bloc"><strong>How to Implement the Authentication Flow with Bloc</strong></h2>
<p>To implement the authentication flow, you will create a dedicated Stateless widget to check if a user has logged in already so that we will know what screen to show the user. The page will display different screens based on the user's authentication state.</p>
<h3 id="heading-authenticationflowscreen"><code>AuthenticationFlowScreen</code>:</h3>
<p>Create a new file called <code>authentication_page.dart</code> in your project's <code>screens</code> directory.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:bloc_authentication_flow/screens/home.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:bloc_authentication_flow/screens/sign_up.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:firebase_auth/firebase_auth.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthenticationFlowScreen</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">const</span> AuthenticationFlowScreen({<span class="hljs-keyword">super</span>.key});
  <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> id = <span class="hljs-string">'main screen'</span>;
  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      body: StreamBuilder&lt;User?&gt;(
        stream: FirebaseAuth.instance.authStateChanges(),
        builder: (context, snapshot) {
          <span class="hljs-keyword">if</span> (snapshot.hasData) {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">const</span> HomeScreen();
          } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">const</span> SignupScreen();
          }
        },
      ),
    );
  }
}
</code></pre>
<p>In the above code, you have a <code>StatelessWidget</code> with a <code>StreamBuilder</code> as the child. The <code>StreamBuilder</code> acts as a judge, using Firebase to check the state changes and if a user has logged in or not. If a user has logged in, it directs them to the home screen, else it goes to the sign-up screen.</p>
<p>Change the home route to <code>AuthenticationFlowScreen</code> to allow the app to check before routing to any page.</p>
<pre><code class="lang-dart">   home: <span class="hljs-keyword">const</span> AuthenticationFlowScreen()
</code></pre>
<h3 id="heading-sign-up-screen">Sign-up Screen</h3>
<p>First, create a new file called <code>sign_up.dart</code> in the <code>screens</code> directory.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:bloc_authentication_flow/screens/home.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter_bloc/flutter_bloc.dart'</span>;

<span class="hljs-keyword">import</span> <span class="hljs-string">'../bloc/authentication_bloc.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SignupScreen</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatefulWidget</span> </span>{
  <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> id = <span class="hljs-string">'login_screen'</span>;

  <span class="hljs-keyword">const</span> SignupScreen({
    Key? key,
  }) : <span class="hljs-keyword">super</span>(key: key);

  <span class="hljs-meta">@override</span>
  State&lt;SignupScreen&gt; createState() =&gt; _SignupScreenState();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_SignupScreenState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">SignupScreen</span>&gt; </span>{
  <span class="hljs-comment">// Text Controllers</span>
  <span class="hljs-keyword">final</span> emailController = TextEditingController();
  <span class="hljs-keyword">final</span> passwordController = TextEditingController();

  <span class="hljs-meta">@override</span>
  <span class="hljs-keyword">void</span> dispose() {
    emailController.dispose();
    passwordController.dispose();
    <span class="hljs-keyword">super</span>.dispose();
  }

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      appBar: AppBar(
        title: <span class="hljs-keyword">const</span> Text(
          <span class="hljs-string">'Login to Your Account'</span>,
          style: TextStyle(
            color: Colors.deepPurple,
          ),
        ),
        centerTitle: <span class="hljs-keyword">true</span>,
      ),
      body: Padding(
        padding: <span class="hljs-keyword">const</span> EdgeInsets.all(<span class="hljs-number">16.0</span>),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            <span class="hljs-keyword">const</span> SizedBox(height: <span class="hljs-number">20</span>),
            <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Email address'</span>),
            <span class="hljs-keyword">const</span> SizedBox(height: <span class="hljs-number">10</span>),
            TextFormField(
              controller: emailController,
              decoration: <span class="hljs-keyword">const</span> InputDecoration(
                border: OutlineInputBorder(),
                hintText: <span class="hljs-string">'Enter your email'</span>,
              ),
            ),
            <span class="hljs-keyword">const</span> SizedBox(height: <span class="hljs-number">10</span>),
            <span class="hljs-keyword">const</span> Text(<span class="hljs-string">'Password'</span>),
            TextFormField(
              controller: passwordController,
              decoration: <span class="hljs-keyword">const</span> InputDecoration(
                border: OutlineInputBorder(),
                hintText: <span class="hljs-string">'Enter your password'</span>,
              ),
              obscureText: <span class="hljs-keyword">false</span>,
            ),
            <span class="hljs-keyword">const</span> SizedBox(height: <span class="hljs-number">10</span>),
            GestureDetector(
              onTap: () {},
              child: <span class="hljs-keyword">const</span> Text(
                <span class="hljs-string">'Forgot password?'</span>,
                style: TextStyle(
                  color: Colors.deepPurple,
                ),
              ),
            ),
            <span class="hljs-keyword">const</span> SizedBox(height: <span class="hljs-number">20</span>),
            BlocConsumer&lt;AuthenticationBloc, AuthenticationState&gt;(
              listener: (context, state) {
                <span class="hljs-keyword">if</span> (state <span class="hljs-keyword">is</span> AuthenticationSuccessState) {
                  Navigator.pushNamedAndRemoveUntil(
                    context,
                    HomeScreen.id,
                    (route) =&gt; <span class="hljs-keyword">false</span>,
                  );
                } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (state <span class="hljs-keyword">is</span> AuthenticationFailureState) {
                  showDialog(
                      context: context,
                      builder: (context) {
                        <span class="hljs-keyword">return</span> <span class="hljs-keyword">const</span> AlertDialog(
                          content: Text(<span class="hljs-string">'error'</span>),
                        );
                      });
                }
              },
              builder: (context, state) {
                <span class="hljs-keyword">return</span> SizedBox(
                  height: <span class="hljs-number">50</span>,
                  width: <span class="hljs-built_in">double</span>.infinity,
                  child: ElevatedButton(
                    onPressed: () {
                      BlocProvider.of&lt;AuthenticationBloc&gt;(context).add(
                        SignUpUser(
                          emailController.text.trim(),
                          passwordController.text.trim(),
                        ),
                      );
                    },
                    child:  Text(
                      state <span class="hljs-keyword">is</span> AuthenticationLoadingState
                            ? <span class="hljs-string">'.......'</span>,
                            : <span class="hljs-string">'Signup'</span>,
                      style: TextStyle(
                        fontSize: <span class="hljs-number">20</span>,
                      ),
                    ),
                  ),
                );
              },
            ),
            <span class="hljs-keyword">const</span> SizedBox(height: <span class="hljs-number">20</span>),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                <span class="hljs-keyword">const</span> Text(<span class="hljs-string">"Already have an account? "</span>),
                GestureDetector(
                  onTap: () {},
                  child: <span class="hljs-keyword">const</span> Text(
                    <span class="hljs-string">'Login'</span>,
                    style: TextStyle(
                      color: Colors.deepPurple,
                    ),
                  ),
                )
              ],
            ),
          ],
        ),
      ),
    );
  }
}
</code></pre>
<p>This code is just a simple Login UI with two <code>textfields</code> and an elevated button. The <code>BlocConsumer</code> widget wraps the <code>Sign up</code> button and listens for changes in the <code>AuthenticationBloc</code> state. When a user presses the button, it dispatches an event to the <code>AuthenticationBloc</code> to initiate the user sign-up process.</p>
<p>Depending on the authentication state, this button may display different feedback or navigate to another screen. It checks for <code>AuthenticationSuccessState</code>, <code>AuthenticationLoadingState</code>, and <code>AuthenticationFailureState</code> states to respond accordingly.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/ezgif.com-video-to-gif--1-.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Img 2: A Login screen showing a login process with 2 out of the 3 states.</em></p>
<h3 id="heading-home-screen">Home Screen</h3>
<p>Create another file called <code>home_screen.dart</code> in the <code>screens</code> directory and add the code below to the file.</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter_bloc/flutter_bloc.dart'</span>;

<span class="hljs-keyword">import</span> <span class="hljs-string">'../bloc/authentication_bloc.dart'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HomeScreen</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-keyword">static</span> <span class="hljs-built_in">String</span> id = <span class="hljs-string">'home_screen'</span>;
  <span class="hljs-keyword">const</span> HomeScreen({<span class="hljs-keyword">super</span>.key});

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            <span class="hljs-keyword">const</span> Text(
              <span class="hljs-string">'Hello User'</span>,
              style: TextStyle(
                fontSize: <span class="hljs-number">20</span>,
              ),
            ),
            <span class="hljs-keyword">const</span> SizedBox(
              height: <span class="hljs-number">20</span>,
            ),
            BlocConsumer&lt;AuthenticationBloc, AuthenticationState&gt;(
              listener: (context, state) {
                <span class="hljs-keyword">if</span> (state <span class="hljs-keyword">is</span> AuthenticationLoadingState) {
                   <span class="hljs-keyword">const</span> CircularProgressIndicator();
                } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (state <span class="hljs-keyword">is</span> AuthenticationFailureState){
                    showDialog(context: context, builder: (context){
                          <span class="hljs-keyword">return</span> <span class="hljs-keyword">const</span> AlertDialog(
                            content: Text(<span class="hljs-string">'error'</span>),
                          );
                        });
                }
              },
              builder: (context, state) {
                <span class="hljs-keyword">return</span> ElevatedButton(
                    onPressed: () {
                      BlocProvider.of&lt;AuthenticationBloc&gt;(context)
                      .add(SignOut());
                    }, child: <span class="hljs-keyword">const</span> Text(
                      <span class="hljs-string">'logOut'</span>
                      ));
              },
            ),
          ],
        ),
      ),
    );
  }
}
</code></pre>
<p>The code above represents the <code>HomeScreen</code> and it's also a simple page that consists of scaffold, a column, and a text widget but the interesting part is the <code>BlocConsumer</code> which is at the elevated button that says logOut. Let's look closely at that.</p>
<p>The <code>BlocConsumer</code> Listens to state changes from the <code>AuthenticationBloc</code>. It has two parameters - listener and builder.</p>
<ul>
<li><strong>listener</strong>: Listens to state changes and reacts based on the current state received from the <code>AuthenticationBloc</code>.</li>
<li>If the state is <code>AuthenticationLoadingState</code>, it shows a <code>CircularProgressIndicator</code>.</li>
<li>If the state is <code>AuthenticationFailureState</code>, it displays an <code>AlertDialog</code> with the message 'Error'.</li>
<li><strong>builder</strong>: Builds the UI based on the current state received from the <code>AuthenticationBloc</code>.</li>
<li>It renders an <code>ElevatedButton</code> labeled "Log Out".</li>
<li>When pressed, it triggers the <code>SignOut</code> event in the <code>AuthenticationBloc</code> via BlocProvider.</li>
</ul>
<p>With the Bloc authentication flow implemented, you can run your Flutter app and test the registration functionalities. Make sure to handle other authentication-related scenarios, such as user Login and password recovery, as required by your app's specifications. Also, you'll want to handle the errors gracefully to give the user a good experience.</p>
<p>If you want to clone the repo, you can check it out on GitHub <a target="_blank" href="https://github.com/emjaycodes/bloc_authentication_flow_article">here</a> and leave a like.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>In this article, we explored building a user authentication flow in Flutter using Firebase for authentication and the Bloc state management pattern for handling application state.</p>
<p>We learned how to set up Firebase in a Flutter project, create Blocs for authentication, and implement the authentication flow using Bloc.</p>
<p>By leveraging the power of Firebase and the predictability of Bloc, you can ensure a secure and seamless user authentication experience in your Flutter apps.  </p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
