[MUSIC PLAYING] MARINA COELHO: Hi, everyone. I'm Marina from
the Firebase team. In this video,
I'm going to cover how to get started with Firebase
authentication in an Android app that was built
with Jetpack Compose. I have many things
to talk about today-- why authenticating users is
important, what sign-in methods Firebase offers, how to enable
these methods to use them in your apps, how to use the
Firebase Emulator Suite to test the authentication service,
how to sign in users and create new accounts,
how to retrieve information from the currently
logged-in user, and how to sign out users
and delete accounts. I've created a simple
app for this video where users can create notes. All notes are displayed in
this list on the main screen. Users can also
click on each item to open the notes so they can
read, update, or delete it. All of the data
for these notes is stored in Cloud Firestore, a
NoSQL database in the Cloud. There is a separate
Firebase Fundamentals video for Cloud Firestore. So in this one, I will just
focus on authentication. If you want to follow along,
the code for this Notes app is available on GitHub,
and you can find the link in the description below. It is important to keep
your users' data safe and secure all of the time. You need to ensure that only
the user who created the data can read, update, and delete it. An authentication system
like Firebase Authentication helps you to grant access only
to the users who own the data. An authentication
system also allows users to sign into their account
on any other device they own, giving them access
to the same data. For example, for many
users of this Notes app, it's important to
be able to access their notes using their Android
phone while they're on the go. Once they're at their
desk, it's probably more convenient for
them to use a web app to read and update their notes. And at home, they might
enjoy using their iPad when sitting on the
couch after a long day. To add Firebase Authentication
to your Android project, first, you need to
create a Firebase project and register your Android
app in this project. If you're new to
Firebase, you might want to know more about
what a Firebase project is and how to set one up. Check out this
video, "How to get started with Firebase on
Android," to learn more. Once you have registered your
Android app with Firebase, you need to add the Firebase
SDK to your Android app. To do this, you will need to
add the required dependencies to your project's Gradle files. Here's a useful tip-- use Firebase's Bill Of
Materials, or BOM for short, to add Firebase dependencies. This will make sure the versions
of all the Firebase SDKs you use work well with each other. After adding the BOM, you
need to add the Firebase authentication library. Next, click on the Sync button
to synchronize your Android project with the Gradle files. If you have followed all
the steps in the setup video I mentioned before, you
probably already added the Google services JSON
file to your Android project. If you haven't already,
you need to do it now, as this file tells
the Firebase SDK which Firebase project to connect to. Now your Android project
is connected to Firebase. And the next step is to go
back to the Firebase console and enable the sign-in
methods that you want to use. Navigate to the Firebase
Authentication dashboard and click on Get Started. OK, there are several
sign-in methods here. In this first group, you
can see authentication with email and password which
allows you to create and manage users that want to sign in
with their email addresses and passwords. There's phone
authentication which allows you to authenticate
users by sending SMS messages to their phones. And there's also
anonymous authentication that you can use to create
guest users in your app. In the second group
of sign-in methods, you can see the so-called
federated identity providers. They allow you to
authenticate users by integrating with any of
these identity providers that you see on the screen. So users can sign into your
app with an existing account that they have with
one of these providers. Also, if you already have
your own custom authentication system, you can connect to
Firebase Authentication SDK too, as you can see in this
third group on the right. It's nice to provide more
than one sign-in method so users can choose how
they want to sign in. But for this video,
I'm going to focus only on one of the most common
sign-in methods, email and password. And I'm going to talk about the
more complex sign-in methods like anonymous authentication
and integration with federated identity
providers in some of the next videos of the
Firebase Fundamentals series. The first step, then, is to
enable the password and email sign-in method here in
the Firebase console by clicking on
the Toggle button. The last thing I
want to show you before we dive into
the authentication code is the Firebase emulator. During the
development phase, you will have to test the creation
of accounts a few times, as well as the sign-in,
sign-out, and deletion account flows. That's why it's
important to do this in a controlled environment
where you won't risk accidentally doing something
wrong with the user base that you have in the
production environment. The Firebase Emulator Suite
is such an environment and allows you to
emulate Firebase on your local
development machine. To use the emulator, you need
to type this command line. As the emulator starts up, you
can see the individual Firebase services being activated
on the emulator and which port they run on. Once the emulator has
finished launching, you can connect your app to it. To do so, you need to configure
firebase.auth in your Android project to run against
the emulators instead of the production project. And you have to do it as
soon as your app starts in the activity's
onCreate function, which, in this application, is
called NotesActivity. There's a lot more you can do
with the Firebase emulator. If you want to better
understand the Firebase Emulator Suite and what environments
you should use it in, check out this video on
the Firebase channel. Perfect. Now the app is connected
to the Firebase emulator. It's time to implement
the authentication flows and test them. To make things easier, I've
prepared an authentication service in the Notes app. This service will handle all
the signups, sign-in, log-out, and delete user account flows. As you can see
here, the service is called from the
ViewModels, which are the classes responsible
for operating all the business logic for the app and handling
the responses that come back from the APIs. The ViewModels
communicate with the UI through these mutable states. Every time you need
to update the UI, you just need to publish a new
state to these mutable objects that the screen is
observing, and the screen will recompose itself
to reflect the changes. On the sign-in and
sign-up screens, this happens with the
email and password that the user is typing. You need to update the screen
with the new characters that are being typed. This type of architecture is
called Model-View-ViewModel, and it's the architecture that
the Android team recommends for Android apps. If you want to understand more
about Model-View-ViewModel, the link to the
official documentation is in the description
of this video. Most Firebase APIs
are asynchronous, which means that the
response won't be immediate. It could arrive at any
point in the future. For example, when you create
an account in Firebase, there are a series of steps that
need to be run in the backend, and the response
will arrive only when all these steps are finished. Meanwhile, it's important
that the main thread doesn't get blocked waiting
for the response, so the app can continue
performing other calls and updating the UI. To handle async
functions, I've created a function called launchCatching
on the NotesAppViewModel. This function can be accessed
by all other ViewModels. launchCatching uses
the launch block. This is Kotlin's way of
calling asynchronous functions, and it handles any
exceptions that might be thrown during the
execution of these functions. Both a SignInViewModel
and the SignUpViewModel call the authentication
service from within this launch-catching
block, so if any errors occur, the application will
not crash and the error will be reported in the logs. Let's first implement
the sign-in flow. Inside the signIn
function, you need to call
signInWithEmailAndPassword. As I mentioned before, this
is an asynchronous call, so you have to use a wait. This will suspend the
function while it's waiting for the response
from the Firebase backend. The good thing is that
this doesn't block the app. Instead, it can continue
processing events, and this is important so it
doesn't become unresponsive. Now let's run the
app and test it. Before recording this video,
I created a test account in the Firebase
Emulator, so I can now use it to sign into the app. Let me type in the email
address and the correct password for this user. And it worked. I am now signed in and
can see all the notes that belong to this user. But what if the user
doesn't have an account yet? You need to allow new
users to create an account for themselves so they
can create their own notes and store them securely
in Cloud Firestore. To do that, you need to
implement the signUp function by calling
createUserWithEmailAndPassword. As you can see
here, this function is very similar
to the signIn one. OK, time to run the app again. Here on the Sign-in
page, I click on the option that says I
don't have an account yet, and that takes me
to the Sign-up page. I type my email,
password, confirm the password I just typed, and
click to create the account. Done. My account was created, and I
was redirected to the Home page where I can create
my first note. And if I navigate to the
Firebase Emulator UI, I can see the new account there. A quick note about the user
experience-- for some apps, asking the user to create an
account before they can start using the app is appropriate. For all the apps,
it might be better to allow users to try
the app before asking them to create an account. This is where anonymous
authentication comes in handy. It allows you to
implement guest users so your users can use
the app without having to create a new account first. We will look at how this works
in one of the next videos. Before you move on to sign-out
and account deletion flows, there is one very important
thing you need to do. At the moment, if you close
the Notes app after signing in and then open it
again, it will still open on the sign-in screen. This happens because
the app doesn't know if there is an
authenticated user or not. The app is configured to
open on the sign-in screen regardless of the
authentication state. To fix this, you need to
change the first screen of the application to
be the splash screen. This screen will be
responsible for checking if there is an authenticated
user in the app. Based on that, it can
decide between navigating to the sign-in
screen or directly to the main screen where the
user can see their notes. First you need to create a
function in the authentication service that retrieves
the current user by adding the following code. If the user does not exist,
this data will be known. If it exists, you have an object
of the type User from where you can retrieve
user information, such as display name, email,
and profile picture URL. Now you need to call
the service function from within the SplashViewModel
as soon as it's initialized. Then the ViewModel can
decide to which screen the app should navigate next. From now on, if you're
signed in and open the app, it will take you directly
to the Notes screen. In addition to checking for
a user during app startup, it's important that the
app is aware of the user's authentication
state at all times so that it can take the user
back to the sign-in screen if the authentication
state changes to signed out or if the account gets deleted. To achieve this, create
an auth state listener. Inside this listener,
add the code that will be executed every
time a new authentication state arrives. Use the Kotlin flow to
admit the current user so any ViewModel in the
app can observe this flow and react to it. The last thing I need to
do is add the listener to Firebase Auth by calling
addAuthStateListener. And you also need to make
sure that this listener is being removed if the
user closes the app. You can do so by calling
removeAuthStateListener inside the awaitClose block. Now that the
authentication services are meeting the current user,
you can use this information in the Notes app of your model. Collect the current user state
in the initialize function of the ViewModel. For each new state, verify
if the user is still signed in by checking
if the user is null. If the user is null, call
the restartApp function. Once the user is
signed in, they may want to sign out of the
account at some point. So let's implement
the signOut function in the authentication service. The signOut function is
probably the simplest one in the Firebase
Authentication API. You just need to call
signOut(), and that's it. The user is signed out of the
account and this application. Let me run the application
and test this function. First, I'm going to click on
the Exit Application icon. To make sure the user
didn't click accidentally, the app will launch this
dialog asking the user to confirm the action. Once I click to confirm, I
am signed out of my account, and the app takes me back
to the sign-in screen. You also have to deal with
the unfortunate possibility that the user will
want to delete their account at some point. So you need to provide
a way for them to do so. All you have to do is implement
the DeleteAccount function in the authentication service
by adding the following code. Let's test this. First I need to sign in
again, so let me type the email and password. Here I am again on
the Notes screen. I'm going to click on
the Delete Account icon and confirm my
action by clicking on this button in the dialogue. Done. My account has been deleted. To confirm it worked,
you can navigate to the Firebase Emulator's UI. And as you can see, the
user that I had previously registered is no longer here. Ideally, when you
delete a user, you also need to delete all data
that belonged to that user in other Firebase services such
as Cloud Firestore, Realtime Database, and Cloud Storage. This sounds like a lot of
work, but, fortunately, there is a Firebase extension that
makes this a lot easier. All you have to do is install
the Delete User Data extension and configure it according
to your project's needs. If you would like to learn
more about Firebase extensions, check out the
Firebase Extensions Hub at extensions.dev, and
read the documentation. As I mentioned earlier, you can
add many other sign-in methods to your Firebase project. If you're interested in knowing
how to add these other methods and how to use other Firebase
services in your Android app, subscribe to our
YouTube channel, and check out the other videos
in the Firebase Fundamentals series. [MUSIC PLAYING]