Dive into Firebase Auth on Flutter: Phone and Anonymous Authentication

Paul Ruiz
Firebase Developers
12 min readNov 3, 2020

Firebase includes a variety of tools to help developers build, grow, and improve their apps. One of the most used of these tools is Firebase Authentication, as it allows developers to restrict who can read or write data to the Firebase backend and provides a secure environment for their user’s data.

This is the third part of a short series covering Firebase Authentication with the FlutterFire plugin. In this article we will learn how to authenticate in Firebase with both Phone Authentication, which uses SMS validation codes, and Anonymous Authentication. In order to completely follow along with the Phone Authentication portion of this article, you will need a physical iOS or Android device that is capable of receiving SMS messages, though you should still be able to get some of the general functionality on an emulator with a test number (we’ll discuss this in a later section). The Firebase Anonymous Authentication feature can be tested on either an iOS simulator or an Android emulator if a physical device is not available.

In the first article of this series we learned how to add Firebase to a Flutter project using FlutterFire, how to register and authenticate a new user in Firebase using an email and password, and how to authenticate a user with an emailed link.

In the second article we learned about third-party identity providers, and how to authenticate in Firebase using GitHub and Google credentials.

If this is the first article you have come across from this series, I highly recommend at least briefly reading over the setup portion of the first article if you are not familiar with the FireFlutter plugin. If you would like an in-depth understanding of Firebase Authentication on Flutter, then I would suggest reading both of the previous articles in their entirety before starting this one. If you’re only interested in phone or anonymous authentication and have already implemented FireFlutter in your app, then starting in this article should be just fine :)

Setup

Before we can get into the code for our app in this article, we’ll need to do a few things to get setup:

  1. Create a Firebase project
  2. Create a new Flutter application
  3. Link the Android portion of our Flutter app to Firebase
  4. Import our dependencies
  5. Lay out the code for our starter app

We can find instructions for steps 1–3 in the first article of this series, or in the official documentation for creating a Firebase project and linking a Flutter app, so I won’t repeat them here. One thing worth mentioning here is that we will need to include our signing key’s SHA-1 for our Android app to use Phone Authentication, which is also covered in the first article. After completing those steps we can open up the pubspec.yaml file in our Flutter project and add the three following dependencies under the dependencies heading:

These will bring in the two required plugins for connecting to our Firebase project and using Firebase Authentication, plus a third-party plugin that will allow us to automatically get the phone number for the user’s device without typing it in. After adding those three lines, be sure to sync your app to pull down these dependencies. This can be done in Android Studio by clicking on the Pub get button in the Flutter commands banner.

For the final setup step, let’s go into main.dart and add the following code for our starter app:

There’s a few things to pay attention to in this starting code. First, you’ll notice that we have already initialized Firebase and our Flutter bindings in the main() method. If we go down into our _MyHomePageState class, you’ll see that we’re saving a reference to the app’s scaffolding context via a key. While we’re not using this now, it will be useful later when we add status messages to our application. Finally, we’ve set the resizeToAvoidBottomPadding property in our Scaffold widget to false. This will prevent drawing errors later when the keyboard takes up a portion of our device screen. Now that we’re set up, let’s dig into using Firebase Phone Authentication.

Phone Authentication

Before we start writing our code to use Phone Authentication, let’s first return to our project in the Firebase console. Once there, we’ll need to go into the Authentication page, which can be found under the Develop tab in the left page navigation part, and over to the Sign-in method tab.

From here we’ll need to open the Phone section under Sign-in Providers and click on the Enable toggle. While we’re here, let’s also click on the chevron next to the text Phone numbers for testing (optional). Once that section is opened, we can add a test phone number and verification code that we can use while developing our app without getting blocked by Firebase’s anti-spamming tools. It’s worth noting that we don’t need to use the device’s actual phone number for testing purposes. It’s actually recommended that we don’t add our real numbers to the allowlist, that way we can use them to test the entire flow later. Once all of that is done, let’s go ahead and click on the blue Save button.

Great, now that we’re set up in the Firebase console, let’s get back to our code. We can start by adding the rest of our class-level fields to the top of _MyHomePageState.

This code gets a reference to the FirebaseAuth instance, creates a pair of TextEditingController objects for keeping track of anything entered by the user in two TextFormField widgets that we will create later, stores a verification ID that we will get through Firebase Phone Authentication, and creates a new object, _autoFill, that we will use for retrieving the physical device’s phone number. The _scaffoldKey object should have already existed in our initial app code, and will be used for displaying status messages in our app.

Next we will need to flesh out our build() method, but let’s do this in stages. First we’ll add a new TextFormField into the widget array in the middle of build(). This will add a new area where users can type in their own phone number.

Following that TextFormField will be a Container widget that wraps a RaisedButton. This RaisedButton will use the autofill plugin that we added to our project earlier to request the user’s physical device’s phone number and populate it into our TextFormField. You’ll notice that this is also an async operation, so the action won’t block our app while retrieving the device’s information.

Back in our build() method we can add an additional Container widget to the array that will wrap another RaisedButton.

This button will take the phone number collected from the user and submit it to Firebase to request a verification code through SMS. Let’s go ahead and just stub out the verifyPhoneNumber() method for now, then we’ll come back to it after we’ve finished our build() method.

To wrap up our build() method, let’s add one more TextFormField and Container/RaisedButton combo to get a field that accepts our SMS verification code and submits it to Firebase.

We can also stub out the signInWithPhoneNumber() method for now.

Once that’s done, our build() method should look like this:

and if we run our app now, the UI should look like this:

Sending the SMS

Now we can get started on the more complex portions of Phone Authentication. Let’s start off by going back into our stubbed out verifyPhoneNumber() method. We will first need to create a series of callbacks that will be used by Firebase to handle the Phone Authentication process. Our first callback will check to see if the user has previously authenticated, and if they can be automatically signed in to Firebase without submitting another SMS verification code:

You’ll notice that we have another new method here: showSnackbar(). This is where our _scaffoldKey object will be used. This method will display status messages for our users at the bottom of the device screen. While this isn’t necessary for Firebase Phone Authentication, it is a nice feature for understanding what’s happening at different stages within our app.

Back in verifyPhoneNumber(), we’ll add our second callback object. This will listen for errors when verifying a user.

There are a couple common error messages that you might see while developing this app. The first one comes up if you have not enabled Firebase Phone Authentication in the console, have not added the SHA-1 signing key for your Android app, or are attempting to verify a phone number on an emulator.

The second comes up if you have attempted to use Phone Authentication on a non-test number too often within a short period of time (during testing I encountered this after about five uses within 30 minutes). This happens because Firebase will stop sending messages to numbers that are not on an allowlist, preventing users from being accidentally spammed by an app. It takes four hours for a number to become unblocked.

The next callback saves the verification ID generated by Firebase when an SMS is sent. This value will be required later when we want to sign our user in.

The final callback in verifyPhoneNumber() will notify our app when an SMS auto-retrieval times out, if supported by the device, and is also able to provide the verification ID for our app.

Once all of those callbacks are created, we can call verifyPhoneNumber() on our FirebaseAuth instance with the callbacks passed in as parameters alongside the device’s phone number and a timeout duration.

Now if we run our app, enter or import a real phone number, and click on the Verify Number button, we should get a text message from Firebase with a verification code. Keep in mind that a test phone number won’t trigger an SMS. Instead, you’ll have to enter the verification code you specified yourself when adding the test phone number to the allowlist to finish the Phone Authentication process.

Signing in

Now we just need to be able to do something with these codes. Let’s handle this by filling out our signInWithPhoneNumber() method. This will be surprisingly simple after building out verifyPhoneNumber(): we just need to create a new AuthCredential by passing in our verification ID and SMS verification code to Firebase’s PhoneAuthProvider, then call signInWithCredential on our FirebaseAuth instance to retrieve our user.

At this point we should be able to retrieve our verification code from an SMS, enter it into the Verification code field, and then click on the Sign in button to authenticate our user. It’s worth noting that we cannot use the autofill plugin here (at the time of this writing) to automatically retrieve the code. Unfortunately they require SMS code messages to start with a tag (<*>), and Firebase does not allow the template for SMS messages to be changed, so this prefix cannot be added.

We should also be able to see our phone authenticated users in the Firebase console user list.

One fun thing to know here is that if our users aren’t English speakers, then we can use the setLanguageCode() method on our FirebaseAuth instance to change the language of the received SMS.

In this case I’m changing it to Mandarin Chinese, and the text message looks like this:

Anonymous Authentication

Now that we’ve gone over Firebase Phone Authentication, let’s take a look at Anonymous Authentication. This method is a bit unique in that it assigns each session-user an ID that uniquely identifies them to the Firebase backend, but isn’t a permanent authentication method — mainly because it isn’t really authenticating anyone. The main reason to use Anonymous Authentication is that it lets us create an onboarding experience for our users that doesn’t require them to create a permanent account immediately, removing some of the friction from your app experience.

This is, by far, the easiest of the authentication types that has been discussed in this series. Let’s start by adding a new Container and RaisedButton to our array in the build() method:

Now we just need to create the signInAnonymously() method. This will call signInAnonymously() on our FirebaseAuth instance, and then save our user.

Before we can sign our users in anonymously, we will need to return to the Firebase console and enable Anonymous sign-in

And that’s it — we can now click on the Anon Sign in button in our app. If we go back into our Firebase console, we should see our new anonymous user.

Non-Permanence

Before we finish this discussion on Firebase Phone and Anonymous Authentications, I wanted to bring up one important thing to consider when using these two types of logins. If the user logs out or changes devices, then their User UID will be completely new and they will not be associated with any previous UIDs that they may have used. If you have a Firebase database set up that relies on this UID to point to the user’s correct data, then they will no longer be able to access it. The best practice here is to attempt to get your users to log in with any of the methods that we’ve discussed in previous posts for a more permanent and secure user record. You can also link their current credentials (and thus their current UID) together with their new ID through the use of Firebase’s account linking feature, though a full discussion on using this with Flutter may be more appropriate for another article.

Conclusion

In this article we have discussed two ways that you can log in your users with Firebase: using Phone Authentication, and Anonymous Authentication. Both of these are great tools for quickly getting your users into your app before going through a longer account creation, though they are currently not substitutes for Firebase’s other, more robust, authentication systems. Hopefully by knowing these two techniques, you will be able to create a smoother and more pleasant app experience for your users.

Resources

--

--

Paul Ruiz
Firebase Developers

Developer Programs Engineer on Android, Maker, @ptruiz_dev