[MUSIC PLAYING]
PETER FRIESE: Hey, everyone.
This is Peter from the Firebase team.
Today, I'm going to show you how your users can
sign into your app with just their email address.
Yes, you heard that right-- no passwords, just their email
address, nothing else.
If you want to know why passwords are such a bad thing,
check out the recent episode of "Better Safe Than Sorry,"
in which my colleague Rachel and I
chat about this in more detail.
Before we dive into the implementation details,
let me show you how signing in with just your email address
looks like in a sample app.
This one here is based on the one
we built in the "Getting Started with Firebase Authentication
on Apple Platforms" video.
So if there is anything in this video that sounds unfamiliar
to you, go and check out that video and then come back here.
So the login screen only has an email field.
And when I enter my email address
and tap on the Login button, the app
tells me that it has sent me an email with a magic link inside.
Magic link?
That sounds intriguing.
So let me check my email.
And sure thing, there is an email
for me telling me to click on this link to sign into the app.
So I tap the link, the app opens, and voila,
I'm signed in.
Amazing.
All I had to do was enter my email address
and tap on a link in an email.
And even better, I didn't have to come up
with a strong password.
And that is a good thing.
That means I don't need to memorize my password
because there is no password.
And if I ever want to sign in to the same app
on a different device, I can use the same flow.
Super convenient.
All I need is access to my email.
Now, I know what you're thinking.
If this is such a smooth user experience,
it surely must be difficult to implement, right?
Well, the good news is that Firebase Auth does
all the heavy lifting for you, so you
can add email and link authentication
to your app in four easy steps.
First, you need to enable email link authentication
in the Firebase Console.
Then, when the user wants to sign in,
you need to send them an email with a magic link.
Firebase can take care of this for you, which makes
sending this email a one-liner.
And if you need more flexibility,
you can implement your own email action handler.
Our documentation has a nice guide
that walks you through this.
Third, when the user clicks on the magic link in that email,
we want to send them straight back into the app.
To make this happen, you will have
to set up dynamic links in the Firebase Console.
And finally, you need to handle the magic link in your app
and pass it back to Firebase Auth
to verify that this is a legitimate request,
and then actually sign the user in.
Four steps.
So why am I still talking about this?
Let's get coding.
If you want to follow along, feel
free to grab the code from our GitHub repository.
In the email link folder, you will find a start-up project.
There is also a folder with the final result.
So if you get stuck or just want to see the result,
feel free to use this.
Let's first go to the Firebase Console
and enable email link authentication.
You will find this in the list of authentication providers
in the authentication section for your project.
We've already enabled email and password authentication
in the introduction video to this series,
so I will just need to enable the email link switch
and then click Save.
Let's now implement sending the sign-in email.
In the start-up project, I've already set up the login UI.
Here is the text input field for the email
the user wants to sign in with.
I've wired this up to a View model
and also made sure that autocorrect doesn't mess up
what the user types.
When the user hits Enter or taps the Login button,
I call sign in with email link, which will then call send
sign-in link on the View model.
Note how I use await to call this asynchronously.
Once the call returns, I will dismiss the login form.
All right, so let's navigate into the View model
to implement this method.
For sending the sign-in email, we
need to provide to parameters-- the email that we
want to send this to and some action code settings.
Let's see.
We can read the email from the email property on the View
model.
Action Code Settings is an object
that we can use to configure the magic link that Firebase
will insert into the email.
It has quite a bunch of properties.
But the ones that are important for us
are the URL and handle code in app.
By setting handle code in app to true,
we tell Firebase to configure the link
so that it jumps right back into the app
without going through the browser.
As for the URL, this needs to be a dynamic link that
belongs to your project.
So for now, let me insert a placeholder
and then come back to it once we have
configured the dynamic link in the Firebase Console.
Let's make sure to wrap the call to send sign-in link
and some basic error handling.
Our View model has an error message property
that we can use to display any error message on the UI
to let the user know that something went wrong.
Oh, and the compiler also reminds us
that this is an asynchronous call
so we need to call it using await.
This will suspend the function until the call
returns or throws an error.
There is one final thing we need to do before we can proceed
to the next step, and that is to keep a note to ourselves
about the email address the user wants to sign in with.
You see, when the user clicks on the link
and comes back to the app, we will send the link to Firebase
so it can sign the user in.
As part of this process, Firebase
needs to verify that the link matches
the email that it was sent to.
This is to prevent someone else from unintentionally signing
in with this link.
SwiftUI has a property wrapper that
allows us to store the email address in the user defaults.
The @AppStorage property wrapper synchronizes the email link
property and the value stored under the email-link link
key in the user defaults.
This makes sure this value even survives an app restart.
Please keep in mind you should never
store any sensitive information like the user's password
or any tokens in user defaults, as this information is not
encrypted or protected in any other way.
If you need to persist sensitive information on the user's
device, you should always use the keychain instead.
It is OK to store the user's email address in the user ID
defaults, though.
So this is what we're going to do once we have successfully
sent them the email.
Usually, when clicking on a link in an email,
this will open the browser.
But as you saw in the demo, clicking
on a link in the sign-in email took me
straight back into the app without even
hopping through the browser.
So what is this magic and how does it work?
And more importantly, how can we add this behavior to our app?
Well, as I mentioned earlier, this is based on dynamic links.
Dynamic links are a Firebase feature that
sits on top of universal links.
It allows you to create links that
look like normal HTTP links but have
some special magic behavior.
Whenever a user clicks on such a link and your app
is already installed, they will be
taken straight into your app instead of a website.
If this is the first time you set up
dynamic links for your Firebase project,
you will have to set up a URL prefix first.
This can either be a website you own,
such as your company domain, or a Firebase-provided subdomain
on page.link.
This is free of cost for you and easy to set up.
You can configure up to 10 URL prefixes.
With that done, let's create a dynamic link
for our sign-in email.
As you see, the URL prefix is pre-selected,
and we can now define a path for the dynamic link.
In the next step, we need to define the target
of this dynamic link.
This should be the URL of your project's email action handler.
If you did not implement a custom email action handler,
this should always be your-app.Firebaseapp.com.
Don't forget to give your dynamic link a name
so that you and your team can identify it easily.
In the next two steps, you need to decide
what happens when the user clicks on your dynamic link
on iOS and/or Android.
For iOS, select Open deep link in your Apple App
and then select your app from the dropdown list.
If your app doesn't appear in this list,
you can create a new Firebase app for it
by clicking on the Add Apple App entry in the dropdown.
Also, keep in mind that you need to provide your App Store ID
and team ID when you create a new app.
Leave all the other settings untouched for now.
You can also ignore the settings for Android and any campaign
tracking options.
Click on the Create button to save the configuration
and create a dynamic link.
Before we can connect this dynamic link to our app,
we'll first have to add it to the list of authorized domains
in Firebase Authentication.
Copy the URL off the dynamic link
and then navigate to Authentication Settings.
And then select Authorized Domains.
Click on Add Domain.
And then add the URL prefix of your dynamic link.
Make sure to just provide the domain, not
the full URL of your dynamic link.
If you forget to do this, you will later
see an error message saying "domain not whitelisted"
when you try to send the sign-in email.
We can now go back to Xcode to connect our app
to our shiny new dynamic link.
But first, let's replace the placeholder
in the actual link configuration with the dynamic link.
Good, I'm glad we didn't forget this.
Now, to make sure our app is registered
as a link target for our dynamic link,
we need to tell iOS that our app is
capable of handling URLs that begin
with the URL prefix of the dynamic link we just created.
To do this, go to Signing and Capabilities
in your Xcode project, and add the associated domains
capability.
Then add a new domain.
The domain needs to start with applinks colon and end
with the URL prefix of your dynamic link.
Nice.
iOS will now launch your app whenever
the user taps on a link that starts with this prefix.
And with this in place, we can now
implement the code to handle the magic link inside our app
and pass it off to Firebase Auth to actually sign the user in.
Swift UI has a view modifier that
makes handling deep links really easy.
The best place to handle the sign-in link
is an Authenticated view.
I created this view to make it easier
to handle the authentication state of the app.
Depending on whether the user is signed in or not,
this view will either display a login form or the application's
main view.
We only need to handle the sign-in URLs when the user is
not signed in, so let's add an unopened URL handler
to the unauthenticated view.
Once we've got the URL, the next step
is to pass it on to Firebase Auth
so it can sign the user in.
To make sure nobody is trying to sign in an unintended user,
we'll first make sure the app is in the middle of an email link
authentication flow by checking if there
is an email in the user default. Remember, we
use the app storage property wrapper
to sync between the user defaults and the email property
wrapper.
If the user defaults don't contain an email address,
the user either hasn't signed in yet
or they have indeed signed in successfully.
But we're definitely not in the middle of the flow,
so we can abort and report an error to the user.
Next, we'll get the absolute URL and check if this is in fact
the sign-in link.
Remember, our app might receive other dynamic links as well,
so we will want to make sure we're not accidentally
trying to sign in with a link that was intended for something
completely different.
And finally, we can use sign in with email link
to sign the user in.
We'll pass in the email that we fetched
from user defaults and the absolute URL
of the sign-in link.
Firebase Authentication will then
verify that the sign-in link was in fact initiated
from this email address.
And because this call can throw an exception,
we need to wrap this call in a Do Catch block
and implement some basic error handling.
If anything goes wrong, we'll let the user know.
Also, note that the call to sign the user in
is asynchronous, which is why we call it using await.
This will suspend the function until the call returns.
Let's make sure our UI doesn't freeze.
Once the call returns, the function resumes
and we issue some details about the user.
Most importantly, we can reset the email address
we stored in user defaults.
This concludes the sign-in flow.
Now, you might be wondering how the UI knows
that the user is signed in.
Here is a quick refresher if you haven't
watched the first episode in this series yet.
When this view model is initialized,
we set up an authentication state listener.
This listener will be called whenever
the user signs in or out.
When this happens, we update the user, authentication state,
and display name properties.
And since the UI is connected to these properties,
it will automatically reflect the state.
Great.
Let me run this flow one more time
to see it in all its glory.
Here is the login screen.
I enter my email address and tap on Login.
To demonstrate that the email address is persisted even
across app restarts, I will now kill the application.
In the meantime, the email has arrived.
And when I tap on the link, this will take me
right into the app.
No jumping in and out of the browser window.
It's all very smooth.
And voila, I'm signed in.
Again, to drive home this point, I
did not have to come up with a password
since this entire flow does not involve any passwords at all.
And there you have it, signing in
with email link authentication to your iOS apps.
I think this is a great way to sign in users without having
to use passwords.
If you've got any questions, leave them in the comments
below or reach out to me on social media.
I'm @PetersPriese on Twitter and @PeterFriese@iosdev.space
Mastodon.
And if this video helped you, give
me a thumbs up and share it with your friends.
Stay safe, and I will see you in the next one.
[MUSIC PLAYING]