Implementing email and password-based authentication on Android using Firebase

As a developer, it’s crucial for your business to have access to your user’s details. Be it to monitor their usage patterns, send promotional campaigns, notify them of critical updates to your services, or for additional cross-selling of new services.

One effective technique to gather user data is via authentication. Or, put simply, a login system that lets your app know when a particular user is using the app.

Implementing a secure authentication system of this kind from the ground up might require weeks of effort, along with you having to learn a server-side framework to build the backend for the same.

But thanks to Firebase, as a mobile (or web) developer, you don’t have to worry about doing all this, as Firebase provides simple APIs that let you easily handle user authentication.

Along with the classic email + password mechanism for authentication which we’ll cover here), Firebase also provides a social and phone number login system, which allows a user to sign in with their social accounts and phone number, respectively—we’ll cover the latter in a future tutorial.

About authentication with Firebase

As outlined earlier, Firebase allows us to perform user authentication by the following means:

  1. Email and password-based authentication (covered in this post)
  2. Social account-based authentication using Google, Twitter, Facebook, etc.
  3. Phone number based authentication

In this blog post, we’ll be covering the first of the three authentication methods in detail. So without any further ado, let’s get started!

Setting up a Firebase project for the app

Before starting, we need to ensure that the app in question is connected to Firebase. To do so, you can find a good tutorial here:

Once done, you need to add the following dependency in order to use Firebase Auth:

dependencies {
    ...
    implementation 'com.google.firebase:firebase-auth:19.2.0'
}

You also need to go to your newly-created app’s Firebase Console and enable the sign-in providers from the Authentication section:

Once you have the project configured, it’s time to get started with the actual authentication implementation.

Step 1: Create a sign-in UI that allows users to provide email and password

Before doing anything else, we need to have a basic UI in place that allows the users to enter their email and password. It should allow users to either create an account or log in to an already-existing account.

<LinearLayout
                android:id="@+id/llLogin"
                android:layout_margin="4dp"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:orientation="vertical">

            <EditText
                    android:inputType="textEmailAddress"
                    android:ems="15"
                    android:layout_gravity="center"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:id="@+id/etEmail"/>

            <EditText
                    android:inputType="textPassword"
                    android:ems="15"
                    android:layout_gravity="center"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:id="@+id/etPassword"/>

            <LinearLayout android:layout_width="match_parent"
                          android:layout_height="wrap_content"
                          android:gravity="center"
                          android:orientation="horizontal">

                <ImageButton
                        android:src="@drawable/ic_login"
                        android:layout_width="72dp"
                        android:layout_height="72dp"
                        android:scaleType="centerCrop"
                        android:id="@+id/btnLogin"
                        android:layout_gravity="center"/>

                <ImageButton
                        android:src="@drawable/ic_sign_up"
                        android:layout_width="72dp"
                        android:layout_height="72dp"
                        android:scaleType="centerCrop"
                        android:id="@+id/btnSignUp"
                        android:layout_gravity="center"/>

            </LinearLayout>

        </LinearLayout>

Here’s a basic XML layout that has 2 EditText widgets allowing us to enter the email and password, followed by 2 Buttons that let the user either sign up or log in to the app.

Step 2: Using Firebase to receive input and perform the login

Once the user decides to either sign up or log in, we have to receive the input provided by them and perform the desired action. The code for doing so is shown below:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        ...
        
        btnLogin.setOnClickListener {
            // get the email and password from the EditText
            val email = etEmail.text.toString()
            val password = etPassword.text.toString()
            // get access to an instance of FirebaseAuth and perform login 
            FirebaseAuth.getInstance()
                .signInWithEmailAndPassword(email, password)
                .addOnSuccessListener {
                    // login successful, update the UI
                    Log.e("TAG", it.user.email)
                }
                .addOnFailureListener {
                    // login failed, probably bad email-password combo or a network issue
                    it.printStackTrace()
                }
                .addOnCompleteListener {

                }
        }

        btnSignUp.setOnClickListener {
            val email = etEmail.text.toString()
            val password = etPassword.text.toString()
            // get access to an instance of FirebaseAuth and create the user account
            FirebaseAuth.getInstance()
                .createUserWithEmailAndPassword(email, password)
                .addOnSuccessListener {
                    // account creation successful, upate the UI and send an account verification email
                    Log.e("TAG", it.user.email)
                }
                .addOnFailureListener {
                    // account creation failed, probably the account already exists or bad network connection
                    it.printStackTrace()
                }
        }

    
    }
  
}

Let’s go through the content covered in the code snippet above.

To login an already-existing user, we use the signInWithEmailAndPassword() method available in the FirebaseAuth class. This method has various callbacks like onSuccess, onFailure, and onComplete, each of which is used to relay the success or failure of the method call.

It’s possible that the user is trying to log into the app without creating an account in the first place. It’s also possible that their email and password combination is wrong—as so on and so forth. The onFailure method comes with an exception that you can use to figure out the exact cause of the failure and handle it accordingly.

Similarly, to allow a new user to sign up, we used the createUserWithEmailAndPassword method, which will create a new user instead. Once the user has been created, we can get their details (like email, UID, etc.)

Step 3: Getting the user’s details and implementing log-out functionality

Once the user has logged in, you can fetch the user by calling the getCurrentUser() method on an instance of the FirebaseAuth class. Depending on the log-in provider, the details you get might vary. The code below showcases all the possible details you can get from a logged-in user:

class MainActivity : AppCompatActivity() {
      
      override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        FirebaseAuth.getInstance().currentUser?.let { currentUser ->
            // the user is already logged in, so get the details from him/her
            
            // uid is unique for every logged in user, and wil always be not-null 
            val uid : String = currentUser.uid 
            // rest of the parameters might be null depending on the auth provider used
            val name: String? = currentUser.displayName
            val email: String? = currentUser.email
            val profilePic : Uri? = currentUser.photoUrl
            val contactNumber = currentUser.phoneNumber
            
        }?: kotlin.run { 
            // currentUser is null, that means the user is not logged in yet!
            signIn()
        }
      }
}

You can then use these details to update your app’s UI and let the users know that they have been logged into the app.

However, once a user has logged in, you might also want to provide them the possibility of logging out of the app. Firebase allows us to do this in an easy manner. To log out a currently logged in user, simply call the following method:

Doing this will set the currentUser to null and sign out the currently logged in user. If you want to perform an action once the user has logged out, you might want to attach an AuthStateListener to FirebaseAuth, allowing you to know when the user has logged in or logged out.

class MainActivity : AppCompatActivity() {
      
      override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        FirebaseAuth.getInstance().addAuthStateListener { 
            
            // this is called everytime the authentication state changes (either the user logs in or logs out)
            
            it.currentUser?.let { 
                // the user is logged in
            }?: kotlin.run { 
                // the user is logged out
            }
            
        }        
      }   
}

With that, the basic email and password auth are now finally implemented in the app, and upon logging into the app, if you go to the Firebase Console, you can see that the user has also been created there.

Step 4: Verifying the created user’s email

To ensure that the user isn’t using gibberish or false emails to create an account in your app, the FirebaseAuth class has a helper method that sends a verification email to the user, and until the user has verified their email, the user is marked as unverified.

To implement this, we can add a small code snippet to our app that will handle this for us:

class MainActivity : AppCompatActivity() {
      
      override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        FirebaseAuth.getInstance().addAuthStateListener {

            it.currentUser?.let {firebaseUser ->
                // the user is logged in
                if(firebaseUser.isEmailVerified){
                    // the user's is verified, proceed normally
                }else{
                    // the user's email is unverified
                    Toast.makeText(this, "Please verify your email", Toast.LENGTH_SHORT).show()
                    firebaseUser.sendEmailVerification()
                }
            }?: kotlin.run {
                // the user is logged out
            }
        }        
      }   
}

To configure the email that’ll be sent to the users, you can head over to your Firebase Console and go to the Templates tab in the Authentication section.

Once here, feel free to edit the email as you’d like.

Step 5: Letting the users change their email and password

As with any authentication system, it’s crucial that you have a system in place that allows your users to update or reset their email and password. Again, as with email verification, Firebase also has helper methods that let you implement this easily. Let’s look at how to implement these features:

class MainActivity : AppCompatActivity() {
 
    fun resetPassword(user: FirebaseUser) {
        FirebaseAuth.getInstance().sendPasswordResetEmail(requireNotNull(user.email))
                .addOnSuccessListener {
                    Toast.makeText(this, "Email sent!", Toast.LENGTH_SHORT).show()
                }
    }

    fun updatePassword(user: FirebaseUser) {
        user.updatePassword("newPassword")
                .addOnSuccessListener {
                    Toast.makeText(this, "Password Updated, please log in again!", Toast.LENGTH_SHORT).show()
                    FirebaseAuth.getInstance().signOut()
                }
    }

    fun updateEmail(user: FirebaseUser) {
        user.updateEmail("[email protected]")
                .addOnSuccessListener {
                    Toast.makeText(this, "Email Updated, please log in again!", Toast.LENGTH_SHORT).show()
                    FirebaseAuth.getInstance().signOut()
                }
    }
  
}

As you can see, the methods are more or less self-explanatory. Each of the methods has a success and failure listener that you can use to notify the user about the action and have them respond appropriately.

As with email verification, you can also configure the email that’s sent when the user opts in to reset their password or updates their email. You can do so by going to the Firebase Console:

And that’s it! By adding a sleek UI, you can create a fully-functional and robust authentication system for free!*

  • Firebase authentication is free for 25,000 users—past that, you’ll have to pay for the service.

Conclusion

In a follow-up post, I’ll cover how one can implement social log-in using a handy library created by the Firebase developers to ease the entire process.

Thanks for reading! If you enjoyed this story, please click the 👏 button and share it to help others find it! Feel free to leave a comment 💬 below.

Have feedback? Let’s connect on Twitter.

Avatar photo

Fritz

Our team has been at the forefront of Artificial Intelligence and Machine Learning research for more than 15 years and we're using our collective intelligence to help others learn, understand and grow using these new technologies in ethical and sustainable ways.

Comments 0 Responses

Leave a Reply

Your email address will not be published. Required fields are marked *