Skip to content

mettiuss/swift-googlesignin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Google Sign In with Firebase in SwiftUI app

While working on my latest iOS app, I had quite a few difficulties finding an up-to-date guide on how to correctly set up Firebase Authentication in Swift 5. I decided to write my first blog post in an attempt to fill this gap.

In this guide, I will show you how to build a simple app that lets users sign in using Google OAuth2.

[signin-animation.gif]

Setting up Firebase

From the Firebase console create a new project, then head to “Authentication” and click on Get started.

Then navigate to Sign-in method and enable the Google authentication flow.

[authentication-google.jpg]

Setting up the SwiftUI app

Add the app to the Firebase project by clicking the button with the iOS logo and compiling the form.

[firebase-app.jpg]

When prompted, download the GoogleService-Info.plist and add it to the root of your Xcode project.


Let’s now install the necessary dependencies, in Xcode navigate to File > Add Package Dependencies… In the search bar type https://github.com/firebase/firebase-ios-sdk and add the “FirebaseAuth” package product to your app.

[xcode-firebase.png]

Now search for the Google Sign in package by typing https://github.com/google/GoogleSignIn-iOS and add the “GoogleSignIn” package product to your app.


Then open the project settings, navigate to "Info" and add a new entry under “URL Types” using the + button. In “URL Schemas” write your REVERSED_CLIENT_ID, which you can find in yourGoogleService-Info.plist file.

[xcode-redirecturl.png]


We have now finished setting up the project, let's move on to the coding part...

In the ExampleApp.swift file we need to initialize Firebase and we have to handle the URL that your application will receive at the end of the Google authentication process.

import SwiftUI
import FirebaseCore
import GoogleSignIn

@main
struct ExampleApp: App {
    init() {
        // Firebase initialization
        FirebaseApp.configure()
    }

    var body: some Scene {
        WindowGroup {
            ContentView().onOpenURL { url in
                //Handle Google Oauth URL
                GIDSignIn.sharedInstance.handle(url)
            }
        }
    }
}

In the ContentView.swift file we need to check if the user is already logged in, and we will to listen for changes in the login status.

import SwiftUI
import FirebaseAuth

struct ContentView: View {
    @State private var userLoggedIn = (Auth.auth().currentUser != nil)

    var body: some View {
        VStack {
            if userLoggedIn {
                Home()
            } else {
                Login()
            }
        }.onAppear{
            //Firebase state change listeneer
            Auth.auth().addStateDidChangeListener{ auth, user in
                if (user != nil) {
                    userLoggedIn = true
                } else {
                    userLoggedIn = false
                }
            }
        }
    }
}

Let’s now build an Authentication class in Authentication.swift

import Foundation
import FirebaseCore
import FirebaseAuth
import GoogleSignIn

struct Authentication {
    @MainActor
    func googleOauth() async throws {
        // google sign in
        guard let clientID = FirebaseApp.app()?.options.clientID else {
            fatalError("no firbase clientID found")
        }

        // Create Google Sign In configuration object.
        let config = GIDConfiguration(clientID: clientID)
        GIDSignIn.sharedInstance.configuration = config

        //get rootView
        let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene
        guard let rootViewController = scene?.windows.first?.rootViewController
        else {
            fatalError("There is no root view controller!")
        }

        //google sign in authentication response
        let result = try await GIDSignIn.sharedInstance.signIn(
            withPresenting: rootViewController
        )
        let user = result.user
        guard let idToken = user.idToken?.tokenString else {
            throw AuthenticationError.runtimeError("Unexpected error occurred, please retry")
        }

        //Firebase auth
        let credential = GoogleAuthProvider.credential(
            withIDToken: idToken, accessToken: user.accessToken.tokenString
        )
        try await Auth.auth().signIn(with: credential)
    }

    func logout() async throws {
        GIDSignIn.sharedInstance.signOut()
        try Auth.auth().signOut()
    }
}

enum AuthenticationError: Error {
    case runtimeError(String)
}

Finally we’ll build a simple Login screen in Login.swift

import SwiftUI

struct Login: View {
    @State private var err : String = ""

    var body: some View {
        Text("Login")
        Button{
            Task {
                do {
                    try await Authentication().googleOauth()
                } catch AuthenticationError.runtimeError(let errorMessage) {
                    err = errorMessage
                }
            }
        }label: {
            HStack {
                Image(systemName: "person.badge.key.fill")
                Text("Sign in with Google")
            }.padding(8)
        }.buttonStyle(.borderedProminent)

        Text(err).foregroundColor(.red).font(.caption)
    }
}

As well as a basic home page in Home.swift

import SwiftUI
import FirebaseAuth

struct Home: View {
    @State private var err : String = ""

    var body: some View {
        HStack {
            Image(systemName: "hand.wave.fill")
            Text(
                "Hello " +
                (Auth.auth().currentUser!.displayName ?? "Username not found")
            )
        }
        Button{
            Task {
                do {
                    try await Authentication().logout()
                } catch let e {
                    err = e.localizedDescription
                }
            }
        }label: {
            Text("Log Out").padding(8)
        }.buttonStyle(.borderedProminent)

        Text(err).foregroundColor(.red).font(.caption)
    }
}

About

Google Sign In with Firebase in SwiftUI app example

Topics

Resources

License

Stars

Watchers

Forks

Languages