Whether you’re building a simple to-do app or building your dream app, authentication helps you personalize the experience with specific information about your users. It is also an important component of privacy and security.

Firebase authentication is a pre-configured background service that makes it easy to integrate mobile applications using the SDK. You don’t need to maintain any back-end infrastructure for the authentication process, and Firebase supports integration with popular identity vendors such as Google, Facebook, and GitHub.

In this tutorial we will show you how to integrate Firebase authentication with your Flutter application. To demonstrate with a practical example, we’ll walk you through the process of setting up an email – password registration and login.

We will go through the following steps.

  • Create a Flutter and Firebase project
  • Set up Firebase for Android, iOS, and the Web
  • Import the Firebase plug-in
  • Initialize the Firebase application
  • Register a new user
  • Users check in and check out
  • Refresh the user
  • Defining validators
  • Establish a sign-in form
  • Set up your profile page
  • Stay logged in

The finished application will look like this.

Create a Flutter and Firebase project

Create a new Flutter project using the following command.

flutter create flutter_authentication

Copy the code

Open the project in your favorite code editor. Here’s how to open it with VS Code.

code flutter_authentication

Copy the code

To integrate Firebase with your Flutter project, you must create a new Firebase project by going to the console.

Add a new project and give it a name. In this example project, we don’t need Google Analytics, so you can disable it. Once you have created your project, you will be directed to your Firebase project dashboard.

Set up Firebase for Android, iOS, and the Web

To use Firebase on Android, iOS, or the Web, you must complete some configuration for each platform. See the complete configuration guide below.

  • Android installed
  • IOS installed
  • Network installation

Now that we have the basic setup to use Firebase, let’s dive into our Flutter application.

Import the Firebase plug-in

Before you start implementing the authentication logic, you need to import the following plug-ins.

  • [firebase_core](https://pub.dev/packages/firebase_core)Firebase authentication is required to use any Firebase service in the Flutter application.
  • [firebase_auth](https://pub.dev/packages/firebase_auth)To gain access to the Firebase authentication service

Add these plug-ins to your pubspec.yaml file.

Dependencies: Firebase_core: ^1.0.4 Firebase_auth: ^1.1.1Copy the code

Initialize the Firebase application

Before you can use any Firebase services in the Flutter application, you need to initialize the Firebase App.

Modify the main.dart file to the following.

import 'package:flutter/material.dart'; import 'screens/login_page.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Authentication', debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: Colors.cyan, ), home: LoginPage(), ); }}Copy the code

Define LoginPage.

import 'package:flutter/material.dart'; class LoginPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Firebase Authentication'), ), ); }}Copy the code

Add a new method to initialize the Firebase App.

Future<FirebaseApp> _initializeFirebase() async {
    FirebaseApp firebaseApp = await Firebase.initializeApp();
    return firebaseApp;
}

Copy the code

Because this method is asynchronous, you must use FutureBuilder in the build method.

class LoginPage extends StatelessWidget { Future<FirebaseApp> _initializeFirebase() async { FirebaseApp firebaseApp = await Firebase.initializeApp(); return firebaseApp; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Firebase Authentication'), ), body: FutureBuilder( future: _initializeFirebase(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { return Column( children: [ Text('Login'), ], ); } return Center( child: CircularProgressIndicator(), ); },),); }}Copy the code

Now, we’re just in asynchronous task completion shows a simple Text widget, others just a CircularProgressIndicator.

Sign up for a new user

When a new user arrives, they must register with Firebase for authentication before logging in.

Create a named fire_auth. Dart new dart files, and define a named registerUsingEmailPassword new ways of ().

class FireAuth { static Future<User? > registerUsingEmailPassword({ required String name, required String email, required String password, }) async { FirebaseAuth auth = FirebaseAuth.instance; User? user; try { UserCredential userCredential = await auth.createUserWithEmailAndPassword( email: email, password: password, ); user = userCredential.user; await user! .updateProfile(displayName: name); await user.reload(); user = auth.currentUser; } on FirebaseAuthException catch (e) { if (e.code == 'weak-password') { print('The password provided is too weak.'); } else if (e.code == 'email-already-in-use') { print('The account already exists for that email.'); } } catch (e) { print(e); } return user; }}Copy the code

Here, we register a new user with the email and password provided, and associate the user’s name with the file.

Various FirebaseAuthException errors can occur, which we have dealt with in the code snippet above.

Users check in and check out

To check in users that are already registered in our application, define a new method, called signInUsingEmailPassword(), that passes the user’s email and password.

static Future<User? > signInUsingEmailPassword({ required String email, required String password, required BuildContext context, }) async { FirebaseAuth auth = FirebaseAuth.instance; User? user; try { UserCredential userCredential = await auth.signInWithEmailAndPassword( email: email, password: password, ); user = userCredential.user; } on FirebaseAuthException catch (e) { if (e.code == 'user-not-found') { print('No user found for that email.'); } else if (e.code == 'wrong-password') { print('Wrong password provided.'); } } return user; }Copy the code

Email and password are used to generate the User object provided by Firebase. This User can later be used to retrieve any other data stored in the account (for example, username, profile picture, and so on).

You can log out of a user using the signOut() method. There is no need to create a separate method for logging out because it is just one line of code.

FirebaseAuth.instance.signOut();

Copy the code

Send email verification

Suppose you want to verify that a user has entered the correct E-mail address before proceeding. To sendEmailVerification, you can use the sendEmailVerification() method on the User object.

user.sendEmailVerification();

Copy the code

Refresh the user

We’ll define another method in the FireAuth class to refresh the User.

static Future<User? > refreshUser(User user) async { FirebaseAuth auth = FirebaseAuth.instance; await user.reload(); User? refreshedUser = auth.currentUser; return refreshedUser; }Copy the code

Defining validators

Our application will have three form fields: name, email, and password. We will create a validator for each field. The validator will help check if the user has entered any inappropriate values in a particular field and display the corresponding errors.

Dart creates a new file called validator.dart, defines a class validator, and specifies three methods in it (each of which will take a String as an argument).

  • validateName()Check if the name field is empty
  • validateEmail()Check that the E-mail address field is empty and use a regular expression to verify that it is properly formatted.
  • validatePassword(), check that the password field is empty and that it is longer than six characters.
class Validator { static String? validateName({required String name}) { if (name == null) { return null; } if (name.isEmpty) { return 'Name can\'t be empty'; } return null; } static String? validateEmail({required String email}) { if (email == null) { return null; } RegExp emailRegExp = RegExp( r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](? : [a - zA - Z0-9 -] {0253} [a zA - Z0-9])? (? :\.[a-zA-Z0-9](? : [a - zA - Z0-9 -] {0253} [a zA - Z0-9])?) * $"); if (email.isEmpty) { return 'Email can\'t be empty'; } else if (! emailRegExp.hasMatch(email)) { return 'Enter a correct email'; } return null; } static String? validatePassword({required String password}) { if (password == null) { return null; } if (password.isEmpty) { return 'Password can\'t be empty'; } else if (password.length < 6) { return 'Enter a password with length at least 6'; } return null; }}Copy the code

Establish a sign-in form

Let’s add a form in LoginPage to accept the user’s email address and password.

Define a GlobalKey.

final _formKey = GlobalKey<FormState>();

Copy the code

Add a form and specify a key.

Form(
  key: _formKey,
  child: Column(
    children: <Widget>[
      // Add widgets
    ],
  ),
)

Copy the code

Next, add two TextFormFields to accept E-mail and passwords.

Form( key: _formKey, child: Column( children: <Widget>[ TextFormField( controller: _emailTextController, focusNode: _focusEmail, validator: (value) => Validator.validateEmail(email: value), ), SizedBox(height: 8.0), TextFormField(Controller: _passwordTextController, focusNode: _focusPassword, obscureText: true, validator: (value) => Validator.validatePassword(password: value), ), ], ), )Copy the code

Add two buttons inside the Form: one for login and one for navigation to the RegisterPage.

Row(
  mainAxisAlignment: MainAxisAlignment.spaceBetween,
  children: [
    Expanded(
      child: ElevatedButton(
        onPressed: () async {
          if (_formKey.currentState!.validate()) {
            User? user = await FireAuth.signInUsingEmailPassword(
              email: _emailTextController.text,
              password: _passwordTextController.text,
            );
            if (user != null) {
              Navigator.of(context)
                  .pushReplacement(
                MaterialPageRoute(builder: (context) => ProfilePage(user: user)),
              );
            }
          }
        },
        child: Text(
          'Sign In',
          style: TextStyle(color: Colors.white),
        ),
      ),
    ),
    Expanded(
      child: ElevatedButton(
        onPressed: () {
          Navigator.of(context).push(
            MaterialPageRoute(builder: (context) => RegisterPage()),
          );
        },
        child: Text(
          'Register',
          style: TextStyle(color: Colors.white),
        ),
      ),
    ),
  ],
)

Copy the code

In the login button, we call the FireAuth signInUsingEmailPassword (), is used to use Firebase certification to perform the login process.

RegisterPage will also contain a Form similar to this, but with an extra field to accept the user’s first registered name.

You can view the user interface code for RegisterPage here.

Set up your profile page

On the ProfilePage, we pass the User object and display the details: the name, E-mail, and whether the User has completed E-mail validation.

The page will also contain two buttons: one to send E-mail validation and one to check out the user.

class ProfilePage extends StatefulWidget { final User user; const ProfilePage({required this.user}); @override _ProfilePageState createState() => _ProfilePageState(); } class _ProfilePageState extends State<ProfilePage> { bool _isSendingVerification = false; bool _isSigningOut = false; late User _currentUser; @override void initState() { _currentUser = widget.user; super.initState(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Profile'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'NAME: ${_currentUser.displayName}', style: theme.of (context).textTheme.bodyText1,), SizedBox(height: 16.0), Text('EMAIL: ${_currentUser.email}', style: Theme.of(context).textTheme.bodyText1, ), SizedBox(height: 1 16.0), _currentUser emailVerified? The Text (' Email verified, style: Theme.of(context) .textTheme .bodyText1! .copyWith(color: Colors.green), ) : Text( 'Email not verified', style: Theme.of(context) .textTheme .bodyText1! .copyWith(color: Colors.red), ), // Add widgets for verifying email // and, signing out the user ], ), ), ); }}Copy the code

The button to send email verification is as follows.

ElevatedButton(
  onPressed: () async {
    await _currentUser.sendEmailVerification();
  },
  child: Text('Verify email'),
)

Copy the code

We’ll also add an IconButton that can be used to refresh the user when an email is authenticated.

IconButton( icon: Icon(Icons.refresh), onPressed: () async { User? user = await FireAuth.refreshUser(_currentUser); if (user ! = null) { setState(() { _currentUser = user; }); }},)Copy the code

Finally, there is the button to check out the user.

ElevatedButton(
  onPressed: () async {
    await FirebaseAuth.instance.signOut();

    Navigator.of(context).pushReplacement(
      MaterialPageRoute(
        builder: (context) => LoginPage(),
      ),
    );
  },
  child: Text('Sign out')
)

Copy the code

Stay logged in

There is one more important thing to do. With most apps, you only need to log in once and it will remember that status for future visits — that is, it will automatically check you in so you don’t have to provide your credentials every time.

In the _LoginPageState class, modify the _initializeFirebase() method to retrieve the current user. If the User is not empty, it means that the User is already logged in to the application, so just navigate to the UserInfoScreen with the retrieved User.

Future<FirebaseApp> _initializeFirebase() async { FirebaseApp firebaseApp = await Firebase.initializeApp(); User? user = FirebaseAuth.instance.currentUser; if (user ! = null) { Navigator.of(context).pushReplacement( MaterialPageRoute( builder: (context) => ProfilePage( user: user, ), ), ); } return firebaseApp; }Copy the code

conclusion

Congratulations to you! You have successfully integrated Firebase authentication. You have successfully integrated Firebase authentication with your Flutter application. As you may have noticed, Firebase authentication not only provides the back-end infrastructure to easily authenticate users, but also predefined automatic login and E-mail authentication methods. And there’s a lot to explore; Firebase Authentication also provides support for integration with a number of identity providers, including Google, Facebook, Twitter, Apple, and more.

You can find the code used in the sample project on GitHub.

If you have any suggestions or questions about this Flutter and Firebase certification tutorial, feel free to contact me on Twitter or LinkedIn.

The postImplementing Firebase Authentication in a Flutter appappeared first onLogRocket Blog.