PETER FRIESE: Hey, everyone.
This is Peter from the Firebase team, and in this video
I'm going to show you how to use Firebase Auth in your app
on iOS and Apple's other platforms.
At the end of this video, you will
know why authentication is important for our apps,
how to set up Firebase authentication, how users work
in Firebase authentication, how to sign users
in and out of your application, how to update your app's UI
state in response to user signing in and out,
how to restore authentication state when relaunching
your application, how to let users sign up for your app,
how to retrieve information about your users,
and last but not least, how to delete user accounts.
This is a lot to get through, so let's get started.
To make it easier to understand how all of this works,
I have created a sample app which
you will be able to download from GitHub to help
you get started.
So the app itself isn't too exciting.
It's just a simple app that lets users
choose their favorite number.
And, at the moment, I store this information
locally in the user defaults, but later
I like to store this data in the Cloud,
so users can retrieve this information
on all of their devices or even share it with their friends.
My goal is to use Cloud Firestore
to manage the users' data.
But before I can do that, users need
to sign in, so I know who they are
and so I can restore the correct information
for each individual user.
Before we can use Firebase authentication,
we need to add the Firebase SDK to our app.
I have already done this for my sample app,
but if you'd like to know how I did that,
check out this other video in which I walk you
through the steps of setting up a Firebase project using
Swift Package Manager.
The next step is to add the Firebase Auth library
to all the targets in which I want
to use Firebase authentication.
To use Firebase authentication, we
need to activate it in the Firebase console,
so this is what I'm going to do first.
Once I've done this, I need to decide
how users can sign into my app.
Firebase supports a number of ways to authenticate.
For example, sign in with Apple, Google sign-in,
email and password, email and link, phone number
authentication, and my personal favorite,
anonymous authentication, and many more.
For each of those, the Firebase team
has created an authentication provider that handles
the authentication flow.
The cool thing about those authentication providers
is that you can use as many as you like in your app,
and that means that your users can choose how they
want to log in to your app.
Some people might want to sign in using email and passwords
because that's what they're used to.
Others might prefer using sign-in with Apple or Google
sign-in, so they won't have to come up with a strong password.
If you use a federated identity provider like Google sign-in
or Facebook login in an app that runs
on any of Apple's platforms, your app
must also offer sign in with Apple.
Check out our video about getting started with sign
in with Apple with Firebase to learn more about this.
You can even implement your own authentication provider,
for example, if you want to integrate
with your corporate authentication system.
I will cover the most important authentication providers
in separate videos, and we will also
look at some of the advanced use cases, such as account linking,
in separate videos.
But in this video, I want to focus on the basics,
and this is where we're going to use email and password
authentication.
Now I want to make it very clear that email and password
authentication is not my preferred authentication
mechanism since we all know that we humans are
very bad at picking strong enough passwords.
However, I think we all have a good understanding
of how email and password authentication works
from a user's perspective, so it is a good example
to explain how Firebase authentication works.
With that out of the way, let me add email and password
authentication to my Firebase project.
To make development easier, I recommend
using the Firebase Emulator.
You can think of the Firebase Emulator Suite
as your own personal instance of Firebase
running on your local development machine.
Since everything runs locally, you
don't run the risk of messing up your production data,
and you also avoid stepping on each other's toes
when you're sharing a development
project with your teammates.
Another benefit is that the Emulator Suite also
works when you're offline or on a slower network.
I start the emulator using the following command line.
This tells the data to persist any user accounts we create
and later restore them the next time I run the same command.
In fact, I've previously created a user account,
and as you can see, the emulator has restored this user
from disk.
This saves quite a bit of time, especially
if you have more than just a few test accounts.
To connect your app to the Emulator Suite,
add the following code to your Firebase setup code.
With this done, let me show you how
to sign in an existing user.
To make this a little bit easier,
I've already implemented the UI for a sign in dialogue
with SwiftUI.
I use the add environment object property wrapper to obtain
the authentication view model from the environment,
so I can share it with other screens in the app.
When I navigate to the authentication view model,
you will see that I created an extension
for all the operations that I want to cover today,
signing in with email and password,
signing up and creating a new user account using email
and password, signing out again, and deleting the user's
account.
One very important thing to keep in mind when
working with Firebase is that most of its methods
are asynchronous.
As Swift developers, we have a couple
of options to call asynchronous APIs.
The most commonly used ones are callbacks, also known
as completion handlers.
You will find them being used a lot in the Firebase
documentation.
Another option is combine.
If you want to learn more about how to use completion handlers
or combine, check out this Twitter thread in which
I explain how to use them.
However, with the release of SWIFT 5.5,
Apple introduced support for async/await
to the SWIFT language which makes calling asynchronous
APIs a lot easier.
The good news is that you can call all asynchronous Firebase
APIs using async/await, so I'm going
to use this whenever we need to make asynchronous calls
in this video.
By the way, if you're interested in how this works,
check out this video in which I explain how Apple made sure
that asynchronous objective-C code can
be called using async/await.
Before I can make any calls to Firebase authentication,
I need to import it.
Then I will add a new property for the user.
And finally, I can call Sign In with Email and Password
to sign the user in with the credentials they
entered in the login screen.
Since this call can throw an error,
I need to wrap it in a Do-Try-Catch block.
If the call was successful, I fetched the user
from the auth result and assigned it
to the user property.
If there was an error, I update the error message.
Let's quickly run the application
to see this in action.
I will sign in using the user account
you can see in the Firebase Emulator on the left.
And once I'm signed in, I can see the main screen of the app,
and in the Xcode log you can see the user's ID.
OK, this works great, but what if I want
to sign up with a new account?
At the moment, the only way to create
a new account for this application
is to go to the Emulator or the Firebase Console
and manually create a new account,
and that's clearly not a great user experience.
So let's add a signup feature to the app.
I've already prepared the UI for this,
so hopefully it should be pretty straightforward to add
this feature to the app.
So what I'm going to do is I will copy and paste
this entire chunk of code and move it down into the Sign
Up with Email Password method of my view model.
And then instead of calling Sign In with Email and Password,
I will call Create User.
Let me run the app, flip over to the sign up page,
and then create a new user account.
Once I tap the signup button, a new user account
will be created, and when I click on the Refresh button
in the Emulator, it will appear in the list of users of my app.
Really nice.
OK.
Before we can talk about signing out and deleting the user
account, we need to take care of a pretty important aspect
of our implementation.
To see what I mean, let me quickly
show you what happens when I relaunch the application.
So as you can see, even though I was logged in before,
I am no longer logged in after restarting the app.
That's a problem because we don't
want people to have to sign in every time they launch the app.
The good news, though, is that Firebase maintains the login
state for us, but we need to make sure
that this information is correctly reflected
in the application state.
So in my sample app I use this Authentication State property
to show the different parts of the UI
depending on whether the user is signed in or not.
I update this property whenever the user signs in,
but I don't do that when the application launches.
Firebase authentication has a really nice feature
that allows us to listen to the authentication
state of the application.
It's called Authentication State Listener.
So let me go ahead and implement this Listener.
And I also need to make sure it is registered when
the view model is instantiated.
This will happen whenever the app launches,
so I can be sure that my listener will be called as
soon as the UI becomes visible.
The listener has a completion handler
that will receive the current Firebase Auth
instance and the user instance.
If the user is signed in, the user instance
will contain information about the user.
And if the is signed out, this parameter will be 0.
So I can just assign this to the user property on the view model
and everything should work smoothly now.
Finally, I can clean up my code a bit
and move the code for updating the authentication
state and the display name into the State Listener.
And now when I launch the app again,
Firebase Auth will call the State Listener
when the application starts up, the State Listener
updates the view model, and the UI will immediately
go into its signed-in state.
Next, let's add an option to sign out.
Again, this is already wired up in the UI.
All I need to do is implement the sign
out method in the view model.
Signing out is probably one of the most simple API calls
in Firebase.
Despite being such a simple call though, there
are still things that might go wrong,
so I need to wrap this in a Do-Try-Catch block.
By the way, did you notice that this
is one of the very few Firebase APIs that are not asynchronous?
That's because it just resets the local authentication state.
No need to call to the back end.
And as a final step, let's consider the sad event
of the user wanting to leave your app completely and delete
their user account.
You probably guessed it.
I've wired this up in the UI already, so all we need to do
is implement the Delete Account method in the view model.
Now that you know the basic principles of Firebase Auth,
there is a lot more you can do.
For example, you can use the user's user ID
to keep track of any documents that belong
to them in Cloud Firestore.
Or you can write security rules that
make sure users can only access the data that
belongs to them in Cloud Storage, Cloud Firestore,
and the realtime database.
You can even determine the currently signed
in user and Cloud functions and use this information
to write serverless backend code that can securely
process the user's data.
And, of course, there are many other ways
to authenticate your users.
We have got a bunch of videos coming up
that cover the most important Firebase authentication
providers.
So why don't you subscribe to our YouTube channel
to make sure you don't miss out on any new episodes?
And, as I promised, the source code for this video
is available on GitHub, so feel free to check it out and use it
in your own apps.
Stay safe, and I will see you in the next one.