Table of contents

TL;DR:

  • Set up Firebase Authentication in your SwiftUI app using Email/Password and Google Sign-In.
  • Enable persistent login with session handling and Firestore user syncing.
  • Support password reset and updates securely through Firebase’s built-in methods.
  • Store and manage user profiles in Firestore using a clean MVVM architecture.
  • Build a modular and scalable auth system that’s production-ready and SwiftUI-friendly.

Introduction:

At Creole Studios, we’re always exploring ways to build secure, scalable, and user-friendly digital experiences — and one of the most crucial parts of any modern app is authentication. Whether you’re building a startup MVP or a full-fledged iOS product, having a robust auth system is non-negotiable.

In this blog, our mobile development team walks you through setting up a complete Firebase Authentication system in SwiftUI, following a clean MVVM architecture. From Email/Password login and Google Sign-In, to persistent sessions, password reset, and Firestore integration — we’ve bundled everything you need into a production-ready solution.

This step-by-step guide is crafted with SwiftUI developers in mind, using the same practical approach we follow when building secure mobile apps for our clients across the globe.

Let’s get started on creating a reliable authentication flow that just works.


Demo Preview

Here’s a quick walkthrough of the app in action — showing login, Google Sign-In, password reset, and Firestore integration


Firebase Setup (Quick Overview)

  1. Create a Firebase project at console.firebase.google.com
  2. Enable Authentication → Google and Email/Password
  3. Add Firestore under Build > Firestore Database
  4. Download GoogleService-Info.plist and add it to your Xcode project
  5. Update your Info.plist with the reversed client ID:
<key>CFBundleURLTypes</key>
<array>
 <dict>
   <key>CFBundleURLSchemes</key>
   <array>
     <string>com.googleusercontent.apps.YOUR_CLIENT_ID</string>
   </array>
 </dict>
</array>

Also enable Keychain Sharing in the Signing & Capabilities section of your target.


Entry Point: ContentView.swift

import SwiftUI
struct ContentView: View {
   @EnvironmentObject var viewModel:AuthViewModel
   var body: some View {
       Group{
           if viewModel.userSession != nil {
  ProfileView()
  } else {
               LoginView()
  }
 }
   }
}
struct ContentView_Previews: PreviewProvider{
   static var previews: some View{
       ContentView()}
}

Core Logic: AuthViewModel.swift

At the heart of your authentication system is the AuthViewModel, which:

  • Handles user login/registration
  • Authenticates with Google
  • Sends password reset emails
  • Syncs user data with Firestore
  • Keeps the user logged in

Here’s a breakdown of the key features:

Email/Password Sign-In

func signIn(withEmail email: String, password: String) async throws {
       self.isLoading = true
       do {
           let result  = try await Auth.auth().signIn(withEmail: email, password: password)
           self.userSession = result.user
           self.isLoading = false
           await fetchUser()
       } catch {
           self.isLoading = false
           self.Error = error.localizedDescription
       }
   }

Authenticates the user and sets the session state.

User Registration

func createUser(withEmail email: String,password: String, fullname: String) async throws {
       self.isLoading = true
       do{
           let result = try await Auth.auth().createUser(withEmail: email, password: password)
           self.userSession = result.user
           let user = User(id: result.user.uid, fullname: fullname, email: email,photoURL: URL(string: ""))
           let encodeUser = try Firestore.Encoder().encode(user)
           try await Firestore.firestore().collection("users").document(user.id).setData(encodeUser)
           self.isLoading = false
           await fetchUser()
       } catch{
           self.Error = error.localizedDescription
           self.isLoading = false
          
       }
   }

Registers a new user and stores their data in Firestore.

Persistent Login

Handled automatically by:

func fetchUser() async {
       guard let uid  = Auth.auth().currentUser?.uid else { return }
       guard let snapshot = try? await Firestore.firestore().collection("users").document(uid).getDocument() else { return }
       self.currentUser = try? snapshot.data(as: User.self)
   }

Firebase persists the session across app restarts.

Google Sign-In

func signInWithGoogle() async -> Bool {
       guard let clientID = FirebaseApp.app()?.options.clientID else {
           fatalError("No client ID found in Firebase configuration")
       }
       let config = GIDConfiguration(clientID: clientID)
       GIDSignIn.sharedInstance.configuration = config
      
       guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
             let window = windowScene.windows.first,
             let rootViewController = window.rootViewController else {
           return false
       }
       do {
           let userAuthentication = try await GIDSignIn.sharedInstance.signIn(withPresenting: rootViewController)
           let user = userAuthentication.user
           guard let idToken = user.idToken else { throw AuthenticationError.tokenError(message: "ID token missing") }
           let accessToken = user.accessToken
           let credential = GoogleAuthProvider.credential(withIDToken: idToken.tokenString,
                                                          accessToken: accessToken.tokenString)
           let result  = try await Auth.auth().signIn(with:credential)
          
           let googleuser = User(id: result.user.uid, fullname: result.user.displayName ?? "" , email: result.user.email ?? "",photoURL: result.user.photoURL ?? URL(string: ""))
           let encodeUser = try Firestore.Encoder().encode(googleuser)
           try await Firestore.firestore().collection("users").document(googleuser.id).setData(encodeUser)
           self.isLoading = false
           await fetchUser()
           self.userSession = result.user
           return true
       }
       catch {
           self.Error = error.localizedDescription
           return false
       }
   }

This is fully async and SwiftUI-friendly. It signs in with Google, gets Firebase credentials, and stores user data in Firestore.

Password Reset and Update

func resetPassword(email: String) async throws{
       self.isLoading = true
       do {
           try await Auth.auth().sendPasswordReset(withEmail: email)
           showMessage = "Link send successfully"
           self.isLoading = false
       } catch {
           showMessage = error.localizedDescription
           self.Error = error.localizedDescription
           self.isLoading = false
           print("Error sending password reset email: \(error.localizedDescription)")
       }
   }
  
   func updatePassword(password:String) async throws{
       self.isLoading = true
       do{
           try await userSession?.updatePassword(to: password)
           self.isLoading = false
       } catch {
           self.Error = error.localizedDescription
           self.isLoading = false
           print("Error sending password reset email: \(error.localizedDescription)")
       }
   }

Securely handles forgotten passwords and password changes.


User Model

Make sure your User.swift looks like this:

struct User: Identifiable, Codable {
   let id: String
   let fullname: String
   let email: String
   let photoURL:URL?
  
   var initials: String{
       let formatter = PersonNameComponentsFormatter()
       if let components = formatter.personNameComponents(from: fullname){
           formatter.style = .abbreviated
           return formatter.string(from: components)
       }
       return ""
   }
}

Folder Structure:


GitHub Project Link

Want to see the full code in action?

👉 Check out the GitHub Repository  Includes the full SwiftUI project with Firebase auth and Firestore setup.

⭐ ️ Start the repo if it helps you — and feel free to contribute!


Final Thoughts

With the setup we’ve outlined, you’ve now built a fully functional, production-ready authentication system in SwiftUI powered by Firebase. You’ve implemented:

  • Email/Password Sign-In and Sign-Up
  • Google Sign-In Integration
  • Persistent login sessions
  • Password reset & update functionality
  • Firestore-backed user data syncing
  • Clean MVVM architecture for maintainability

At Creole Studios, we specialize in crafting secure, scalable mobile apps with seamless user experiences — and authentication is at the heart of it all. Our mobile development team has deep experience working with SwiftUI, Firebase, and modern architectural patterns to build iOS solutions that perform flawlessly in real-world scenarios.

If you’re a startup, enterprise, or entrepreneur looking to build or improve your iOS application, Creole Studios is the right technology partner to help you bring your vision to life — with speed, quality, and long-term reliability.

Let’s connect to build your next SwiftUI app the right way.


Mobile
Sagar Makwana
Sagar Makwana

Software Engineer

Launch your MVP in 3 months!
arrow curve animation Help me succeed img
Hire Dedicated Developers or Team
arrow curve animation Help me succeed img
Flexible Pricing
arrow curve animation Help me succeed img
Tech Question's?
arrow curve animation
creole stuidos round ring waving Hand
cta

Book a call with our experts

Discussing a project or an idea with us is easy.

client-review
client-review
client-review
client-review
client-review
client-review

tech-smiley Love we get from the world

white heart