Seamless Google Sign-In With Supabase & SwiftUI

by Alex Braham 48 views

Hey guys! Let's dive into something super cool – integrating Google Sign-In into your SwiftUI app using Supabase! This is a fantastic way to handle user authentication, making your app user-friendly and secure. We'll walk through the whole process, from setting up your Supabase project to the final implementation in your SwiftUI code. Trust me, it's easier than you might think, and the payoff is huge.

Setting the Stage: Supabase and Google Cloud Configuration

Alright, before we jump into the code, let's get our ducks in a row. We need to set up both Supabase and Google Cloud to work together. Don't worry, I'll guide you through each step. First things first, head over to Supabase and create a new project. Give it a cool name, choose your region, and get it set up. Once your project is ready, navigate to the Authentication section. This is where the magic happens.

Next, enable Google Sign-In. You'll need to grab your Google OAuth Client ID and Client Secret. To get these, you'll need to go to the Google Cloud Console. Create a new project or select an existing one. Then, go to APIs & Services > Credentials. Click on + Create Credentials and select OAuth client ID. You'll be prompted to configure your OAuth consent screen first. This is where you'll add information about your app, like its name, and select the scopes you need (like the user's email address and profile). After configuring the consent screen, you'll be able to create your OAuth client ID. Select iOS as the application type, enter your app's Bundle Identifier, and you'll get your Client ID and Client Secret. Make sure to save these securely! Back in Supabase, paste these details into the Google Sign-In configuration fields, and you're good to go. This connection between your app, Supabase, and Google is crucial for secure and smooth authentication. This groundwork is essential before we get our hands dirty with some code. Remember to keep all of your API keys and secrets safe! This is the most crucial step of building and deploying your app.

Detailed Setup in Supabase

  • Project Creation: Start by creating a Supabase project. Choose a descriptive name and a suitable region for your users.
  • Authentication Settings: Within your Supabase project, locate the Authentication settings. This area is the hub for managing your sign-in methods.
  • Enabling Google: Activate Google Sign-In. You'll need the Google OAuth credentials.
  • Google Cloud Console: Create an app in Google Cloud Console. This involves setting up OAuth client ID, and the OAuth consent screen.
  • OAuth Credentials: Enter the iOS bundle ID of your app.
  • Client Secrets: The Client ID and Client Secret generated here is needed to setup Google sign-in.
  • Saving and securing keys: Make sure to keep the keys secret and use environment variables.

SwiftUI Implementation: Crafting the User Interface

Now, let's get into the fun part: the SwiftUI code! We'll create a simple UI with a Google Sign-In button. When the user taps this button, we'll initiate the Google Sign-In flow, and upon successful authentication, we'll securely store the user's information within Supabase. I'll break down the code into manageable chunks, so you can easily follow along. Let's get started with the essential imports and the basic structure of our view.

First, make sure you have the Supabase Swift package installed in your project. You can add it via Swift Package Manager. Then, import the necessary modules, like SwiftUI and Supabase. Next, create a simple view, let's call it ContentView, with a state variable to hold the user's session. The core of your UI will be a button that triggers the Google Sign-In process. I will show you how to structure the views, handle the button tap, and manage the user's session within Supabase. The goal is to provide a smooth user experience while ensuring robust security.

SwiftUI Code Walkthrough

import SwiftUI
import Supabase

struct ContentView: View {
    @StateObject private var session = SessionStore()

    var body: some View {
        NavigationView {
            VStack {
                if let user = session.session?.user {
                    Text("Welcome, \(user.email ?? "Guest")!")
                } else {
                    Button("Sign in with Google") {
                        Task { await session.signInWithGoogle() }
                    }
                    .buttonStyle(.borderedProminent)
                }
            }
            .padding()
            .navigationTitle("Supabase Google Sign-In")
        }
    }
}

class SessionStore: ObservableObject {
    @Published var session: Session? = nil

    init() {
        Task { await getSession() }
    }

    @MainActor
    func getSession() async {
        session = try? await supabase.auth.session
    }

    func signInWithGoogle() async {
        do {
            let result = try await supabase.auth.signIn(with: .oauth(provider: .google))
            session = result.session
        } catch {
            print("Error signing in with Google: \(error)")
        }
    }

    func signOut() async {
        do {
            try await supabase.auth.signOut()
            session = nil
        } catch {
            print("Error signing out: \(error)")
        }
    }
}

Here’s a breakdown of what’s happening in this code:

  • Imports: We import SwiftUI and Supabase to use the necessary functionalities.
  • ContentView: This is the main view of our app.
  • @StateObject SessionStore: We use SessionStore to manage the user's authentication session.
  • UI Elements: The view conditionally displays different content based on whether a user is logged in.
    • If Logged In: Displays a welcome message with the user's email.
    • If Logged Out: Displays a