Firebase Authentication in SwiftUI

Sign in with Google

Learn how to authenticate user with Sign in with Google and Firebase Authentication

Marwa Diab
Firebase Developers

--

Photo by Brett Jordan on Unsplash

In the previous part of this series, we set up Firebase and implemented Firebase Anonymous Authentication, and prepared the AuthManager class for signing in and linking accounts.

“You can let your users authenticate with Firebase using their Google Accounts by integrating Google Sign-In into your app.” ~ Firebase Documentation

Set up Sign in with Google

In order to do that, we need to add the Google Sign-In SDK to our SwiftUI project, and then enable Google Sign-In in your Firebase project.

Adding GoogleSignIn-iOS SDK package in Xcode.
Add the GoogleSignIn-iOS SDK package.
Add new provider in Firebase console.
Click on Add new Provider to add the Google authentication provider.
Enable Google provider in Firebase console.
Enable the Google provider and click Save.
Download updated GoogleServices-Info.plist file.
Download a new copy of GoogleServices-info.plist.

I used GoogleSignIn-iOS version 7.0.0, which includes some changes from the previous versions. (e.g. how to configure the ClientID).

  • Before implementing Google Sign-In, you need to add a custom URL scheme to Xcode project, to do so follow step number 1 here.
  • Then, add theGIDClientID in info.plist as explained here, copy the ClientID value from your GoogleServices-info.plist file.

Implement Google Sign-in

  1. Inside AuthManager, create a method named googleAuth(user:) that takes GIDGoogleUser
  2. Define AuthCredentials using the Google auth tokens (idToken and accessToken) from the given GIDGoogleUser.
  3. Then call the previously created authenticateUser(credentials:) and pass the credentials we just defined to link or sign-in with Firebase.
// import GoogleSignIn
func googleAuth(_ user: GIDGoogleUser) async throws -> AuthDataResult? {
guard let idToken = user.idToken?.tokenString else { return nil }

// 1.
let credentials = GoogleAuthProvider.credential(
withIDToken: idToken,
accessToken: user.accessToken.tokenString
)
do {
// 2.
return try await authenticateUser(credentials: credentials)
}
catch {
print("FirebaseAuthError: googleAuth(user:) failed. \(error)")
throw error
}
}

Create a new Swift file named GoogleSignInManager.swift in the Model folder, and add the following code:

import GoogleSignIn

class GoogleSignInManager {

static let shared = GoogleSignInManager()

typealias GoogleAuthResult = (GIDGoogleUser?, Error?) -> Void

private init() {}

@MainActor
func signInWithGoogle() async throws -> GIDGoogleUser? {
// 1.
if GIDSignIn.sharedInstance.hasPreviousSignIn() {
return try await GIDSignIn.sharedInstance.restorePreviousSignIn()
} else {
// 2.
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else { return nil }
guard let rootViewController = windowScene.windows.first?.rootViewController else { return nil }

// 3.
let result = try await GIDSignIn.sharedInstance.signIn(withPresenting: rootViewController)
return result.user
}
}

// 4.
func signOutFromGoogle() {
GIDSignIn.sharedInstance.signOut()
}
}

Here is what happens in this code snippet:

  1. Check if a user has previously signed in. If yes, then restore and return the user’s sign-in. Otherwise, move on to the regular sign-in process.
  2. Get the rootViewController by accessing it through the shared instance of your app's UIApplication instance. The Google Sign-In SDK uses rootViewController to present the browser pop-up that hosts the sign-in flow.
  3. Start the sign-in process by calling signIn() from the shared instance of the GIDSignIn class.
  4. Create a function that calls signOut() from the shared instance of the GIDSignIn class to sign out from Google. This function will be called later in AuthManager.

In LoginView, import GoogleSignInSwift, and uncomment GoogleSignInButton.

To use Google Sign-In in your SwiftUI view, add the following code to your view, right after the body:

func signInWithGoogle() async {
do {
guard let user = try await GoogleSignInManager.shared.signInWithGoogle() else { return }

let result = try await authManager.googleAuth(user)
if let result = result {
print("GoogleSignInSuccess: \(result.user.uid)")
dismiss()
}
}
catch {
print("GoogleSignInError: failed to sign in with Google, \(error))")
// Here you can show error message to user.
}
}

I used GoogleSignInButton for this demo, but you can create your custom button and call signInWithGoogle() from your button’s action.

Lastly, in AuthManager, add a function named firebaseProviderSignOut(user:). In this function, iterate over all the providers for the signed in user, and check if one of the providers is google.com. If so, call signOutFromGoogle to sign out from Google.

Then, in the signOut function, replace // TODO: Sign out from signed-in Provider. with firebaseProviderSignOut(user).

func firebaseProviderSignOut(_ user: User) {
let providers = let providers = user.providerData
.map { $0.providerID }.joined(separator: ", ")

if providers.contains("google.com") {
GoogleSignInManager.shared.signOutFromGoogle()
}
}

Take it for a spin

Run the app on your phone or on the iOS Simulator. You should now be able to sign in and link with Google, as well as sign out again.

Firebase user record authenticated with Google provider.
Firebase user with Google provider.

Note

If you authenticated anonymously and then linked with Google credentials, Firebase will not create a new user, but will update identifier and providers on the anonymous user.

Next Steps

Now that users can authenticate using Google, let’s add Sign in with Apple next.

--

--