PETER FRIESE: Hey, everyone.
This is Peter from the Firebase team.
In this video, I'm going to show you
how to implement Google Sign-In using Firebase Auth in your app
on iOS.
This video assumes that you know the basics about Firebase Auth
already.
If you'd like a little refresher,
I recommend you watch my introductory video first
and then come back here.
At the end of this video, you will
know how Google Sign-In works, how
to handle the sign-in flow in your iOS app,
and how to sign out again.
Let's get started.
I've created a sample app to demonstrate
how you can implement Google Sign-In in your app.
The code is available in this GitHub repository.
There is a start up project you can use
if you want to follow along.
But if you just want to see the final result
or if you get stuck, there is also a folder
with the final finished site.
The app allows users to choose their favorite number
and then stores it locally in user defaults.
This is great for now.
But I like to implement a feature that
allows users to retrieve their favorite number
on all their other devices or share it
with their best friends.
Cloud Firestore sounds like a great tool
to implement this kind of data storage.
But before I can store my users favorite numbers in Cloud
Firestore, I need to get hold of some unique identifier
that I can use to tell all of those favorite numbers
apart and know exactly which user has which favorite number.
Firebase authentication provides access to such an identifier.
Each user has a unique identifier called the UID.
Whenever a person signs up to your app using
Firebase authentication, their newly created user account
gets an identifier that is unique to your Firebase
project.
Before we can use Firebase authentication,
we need to add the Firebase SDK to our app.
I've 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.
However, since I already did this in the previous video
about Firebase Auth, I don't need to do this again.
To allow users to sign into my app with Google Sign-In,
I need to add the Google Sign-In SDK.
The Google Sign-In SDK is not part of the Firebase SDK.
It's a separate download, just like other authentication
providers, such as Facebook.
So before I can use it, I need to add the Google Sign-In
SDK to my Xcode project using Swift Package Manager.
Let me open the add packages dialog
and then place the URL of the Google Sign-In SDK
into the search field.
After a short moment, I can see the readme of the package.
The Google Sign-In SDK team has just
released a new major version of the SDK, which
makes configuring the SDK easier than before.
So let's choose up to next beta version
and enter the version number of the latest release.
I'll click on Add Package.
And Xcode will go and fetch the package information
by downloading the package file.
Once that's done, I can select both the Google Sign-In
and Google Sign-In Swift library,
and then click on the Add Package button
to add them to my Xcode project.
There is one more step we need to complete in Xcode before we
can activate Google Sign-In in the Firebase Console.
And this is to add the reverse client
ID to the list of URL schemes.
You can find the reverse client ID in the Google services info
[INAUDIBLE] file.
Copy it and then go back into your target configuration.
Navigate to the Info tab.
Export the URL type section.
Then tap the plus button to create a new URL type
and paste the reverse client ID in the URL schemes field.
Leave all the other fields untouched.
To use Firebase Authentication, we
need to activate it in the Firebase Console.
But as you can see, I already did this for my project,
so no need to do it again.
However, I do need to enable Google
Sign-In in the list of authentication providers
for my app.
You can enable and use as many authentication providers
in your app as you like.
By doing so, you enable users to sign
in using their preferred authentication mechanism.
Some users might prefer signing in with email and password.
While others might prefer Google Sign-In or sign in with Apple,
as this gives them this really smooth one-tap login
experience.
This also allows you to let users link
multiple sign in mechanisms.
For example, if your user signed in using email and password
but they later would like to connect their Google
account to your app, that's possible
if you implement account linking.
This is something we will look at in one of the next videos.
In this video though, I want to show you
how to implement Google Sign-In, so let me go ahead
and activate the Google Sign-In authentication provider.
One thing you need to keep in mind.
If you use any OAuth-based authentication mechanism
such as Google Sign-In or a Facebook login,
Apple's App Store review guidelines
require you to also implement sign in with Apple.
There are some exceptions to this rule.
So I recommend you check out the current version of the App
Store review guidelines to be on the safe side.
By the way, if you forget to enable a provider,
Firebase Auth will throw an error message
when you try to sign in.
That's one of the reasons why you
want to implement some error handling in your app.
It makes it a lot easier to figure out
what's wrong when things aren't working as expected.
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 slow network.
I've already installed and configured
the Firebase Emulator Suite in the previous video.
So feel free to check this out if you'd
like to see how to do this for yourself.
I'll start the emulator using the following command line.
This tells the emulator 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.
Now, with all this preliminary work out of the way,
I can start implementing Google Sign-In in my app.
The first thing I want to do is add a Google Sign-In button
to my login view.
The Google Sign-In SDK contains a sign in button.
But I want more control.
So I will add a custom SwiftUI button to my view.
Let's take a look.
So basically, it is a SwiftUI button.
And inside the label closure I use
a text view to display the text "Sign in with Google".
To make it look like a real button,
I set the button style to bordered.
And I also set the foreground color of the text
depending on whether we're in dark or light mode.
For the colorful G logo, I put an image view
in the background of the text view
and make sure it is aligned to the left side of the text view.
The logo should have a width of 30
and be aligned in the center of its frame.
Now this is starting to look quite nice.
But the logo and the text overlap in an unsightly way.
So I will use the frame view modifier
to tell the label to use all the available space.
In SwiftUI, the order of the view modifiers matter.
So it is really important to apply the frame modifier
before the background.
Otherwise, the logo will not be pushed out to the left edge.
And finally, I will add some vertical padding
to the text to make sure the button has the same height
as the login button just above.
When the user taps on the button,
I will call the sign in with Google function, which
will forward the call to the view
model to sign the user in using Google.
But before we can implement this function,
let's talk about how the process of signing in a user
to Firebase works when using an OAuth provider.
There are three main steps to this process.
First, the user has to sign in to the OAuth provider.
And you will be using the provider's SDK
or their endpoint to handle this step.
If the user signed in successfully,
you will receive an ID token for this user.
Take this ID token and any additional information that
might be required and create a credential object using one
of Firebase's OAuth providers.
There is a generic OAuth provider, but also
some specialized ones, like the one for Google Sign-In.
And finally, use this credential object
to sign in to Firebase and exchange the provider's ID
token for a Firebase ID token.
But before we can actually call the Google Sign-In SDK,
we need to configure it using your app's OAuth client ID.
There are two ways to do this, one using your project's target
properties and the other one using the GID configuration
object.
Remember the updated configuration
flow I told you about?
Well, for using this first way to configure the Google Sign-In
SDK, you don't even need to write any code.
Let me show you how.
First, let's get the client ID for our project.
You can get this by looking into your project's Google services
[INAUDIBLE] file or look it up on the Google Cloud Console.
Remember, every Firebase project is also a Google Cloud project,
so you can see all your project's details by visiting
the Google Cloud Console.
To get the client ID for your project,
go to the Google Cloud Console at console.cloud.google.com,
then find APIs and Services in the navigation bar on the left.
On the fly out menu, select credentials to see all API keys
and/or client IDs for your project.
You should now see an OAuth2 client ID for your iOS project.
It's name should start with iOS client and the bundle
ID of your iOS app.
Click on this item to see its details.
In the next screen, you will see the client ID and the iOS URL
scheme for this OAuth client ID.
Copy the client ID.
Alternatively, if you don't want to use the Google Cloud
Console, you can just open your project's Google services
[INAUDIBLE] file.
The client ID and the reverse client ID
are at the very top of the file.
In the next step, we will add this client ID
to our app's target properties.
First, select the project's target
in the project configuration.
Then hover over the Custom Target properties table
and click one of the little plus icons.
This will insert a new key.
Name the key GID client ID.
Make sure the type is set to string.
And then place the client ID into the value column.
If you don't want to use this approach,
you can also configure the Google Sign-in client SDK
programmatically.
Let's first import the Google Sign-In module,
so we can use it in our view model.
Next, we will fetch the client ID
from the project's Google services [INAUDIBLE] file.
But instead of reading the file directly,
we can use the options object on the Firebase app instance.
This is populated when you call FirebaseApp.configure
at application startup.
After reading the client ID, we create
a GID configuration object and configure the shared GID
sign in instance with it.
The Google Sign-In client SDK will always
try to read the property from your app's target properties
first, and then overwrite it with
any programmatic configuration you might be using.
To help Google Sign-In to present its sign in flow
correctly, we also need to provide a reference
to the presenting view controller.
This is particularly important on devices
with a larger screen.
You will want to make sure the sign in dialogue
appears in the center of the screen
and not somewhere tucked away in a sidebar.
Now that we've got everything in place,
we can invoke the sign in flow by calling
GIDsignin.chatinstance.signin.
When I open the code completion for the sign in method,
I can see all the available overloads.
The first ones all require me to implement a completion handler,
as we can see by looking at their signature.
And these other ones here allow me
to use a single way to call them,
which will make my code look a lot nicer.
So let me call this method and pass in the root view
controller.
And now I will try to assign the result of this method call
to a local variable.
I will use try await since I want to call
this method asynchronously.
But there is a warning which tells me
that this method needs to be called
from an asynchronous context.
When I click on the error message,
Xcode offers two different fixes for this.
Since I am interested in getting the return value of this call,
I will pick this first one here, which adds the async keyword
to the function signature.
And now I need to wrap the call in a
do catch block to properly handle any errors.
Unfortunately, Xcode doesn't have a quick fix for this.
So I'll have to implement this manually.
If an error is thrown, we will return false.
Otherwise, we will return true.
So this was the first step.
In the next step, we will extract
the ID token and the access token
from the result of this call.
If there is no ID token, we will throw an error.
And now, let's use the Google OAuth provider
to create a credential object from the ID
token and the access token.
And finally, we can use this credential object
to sign into Firebase.
The OAuth object has a method sign in with credential
that takes our credential and returns a Firebase user.
Since this is a server call, we need
to call this function asynchronously using try await.
Let's extract the user from the result,
and then print a little log message.
Sweet, we are now ready to run the application.
I'll be using a demo account that
has two-factor authentication enabled to provide
that extra layer of security.
So here I am in the application.
And I am not yet signed in.
I open the sign in dialog.
And here is the Sign In button.
All right, let me tap on it to trigger the sign in flow.
iOS will show this alert to let the user know
that we're now about to use a third party to sign in.
Once I tap on Continue, the Google Sign-In dialog
will appear.
And you will notice that this is actually
running in the web browser.
I can now type in the credentials for the Google
account I want to sign in with.
Since this user has 2FA enabled, I
will now be given a number of options
to receive the second factor, for example,
by using an authenticator app, like Google Authenticator,
or receiving a one-time code by SMS.
When running this on a physical device,
the verification code by SMS is the smoothest option,
as iOS will offer to autofill the code for me
once it has arrived in the messages app.
And voila, I am signed in.
In the previous video, I showed you
how to make sure the app retains its authentication
state across launches by registering
an authentication state listener.
And as expected, this works for any authentication provider.
So if I quit the app and then launch it again,
I am still signed in using my Google account.
Signing the user out works just like for all the other Firebase
authentication providers.
A call to oauth.signout is all that it takes
to sign the user out locally.
Firebase will remove the cached ID token from the keychain,
so the next time the user starts the app,
they will have to sign in again.
Keep in mind that you will have to reset
your app into an unauthorized state after a call to sign out.
The easiest way to do this is to use the authentication state
listener and reset the UI when you receive nil as the user.
As you can see in my implementation,
it will reset the UI and authentication
state when it receives nil.
And there you have it.
Your users can now sign into your app using Google Sign-In.
In my opinion, federated identity providers,
like Google Sign-In and Sign In with Apple
are a much better option than signing in
with email and password.
From the user's perspective, it is so much more convenient.
You don't have to come up with a new and strong enough password.
And since most of the providers remember your username,
you don't even have to type in your email
address all of the time.
Another benefit is that most federated identity providers
support second factor authentication, which
adds an extra layer of protection for your users.
So happy faces all around.
As mentioned earlier, the sample app
is available on our GitHub repository.
And the link is in the description below.
Hey, if this video helped you, I'd
love it if you could give me a thumbs up,
so I know you'd like to see more content like this.
Also, be sure to check out the Firebase Fundamentals playlist,
as we've got a bunch of other videos
about Firebase Auth and all the other Firebase features coming
up.
Stay safe.
And I will see you in the next one.