Skip to main content
Swift for iOS Development
CHAPTER 23 Beginner

Authentication in iOS Apps

Updated: May 16, 2026
7 min read

# CHAPTER 23

Authentication in iOS Apps

1. Introduction

If you are building an app with a global database, you must control who has access to it. You cannot allow anonymous users to delete other people's posts or view private profile data. Your application must establish identity. Building a secure login system from scratch involves hashing passwords, managing JWT tokens, and handling complex encryption. Fortunately, Google's Firebase SDK provides FirebaseAuth, an industry-grade security wrapper that handles this instantly. In this chapter, we will master Authentication in iOS Apps, learning how to create secure accounts, process logins, and manage persistent user sessions.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Enable Email/Password authentication in the Firebase Console.
  • Utilize the Auth.auth().createUser method to register new users.
  • Utilize the Auth.auth().signIn method to authenticate existing users.
  • Retrieve the unique User ID (UID) for database authorization.
  • Listen to global authentication state changes to dynamically swap UI screens.

3. Enabling Authentication in Firebase

Before writing Swift code, you must explicitly enable the login module on Google's servers.
  1. 1. Open the Firebase Web Console.
  1. 2. Navigate to Authentication in the left sidebar.
  1. 3. Click Get Started, then click the Sign-in method tab.
  1. 4. Select Email/Password, toggle it to "Enable", and click Save.

4. Creating a User Account (Sign Up)

Let's build the logic to securely register a new user. We must import the FirebaseAuth package.
swift
123456789101112131415161718192021
import Foundation
import FirebaseAuth

@MainActor
class AuthViewModel: ObservableObject {
    
    // The Signup Function!
    func createAccount(email: String, pass: String) async {
        do {
            // We ask Firebase to create the user securely!
            // This is asynchronous, so we must 'try await'
            let result = try await Auth.auth().createUser(withEmail: email, password: pass)
            
            // If successful, Firebase generates a massive, unique, unguessable String (UID)
            print("Successfully created account! User ID: \(result.user.uid)")
            
        } catch {
            print("Failed to create account: \(error.localizedDescription)")
        }
    }
}

5. Logging In (Authentication)

The login process is mathematically identical, but uses the signIn method instead.
swift
1234567891011
func login(email: String, pass: String) async {
    do {
        // Firebase checks its secure vault to see if the password matches
        let result = try await Auth.auth().signIn(withEmail: email, password: pass)
        
        print("Welcome back! Your ID is: \(result.user.uid)")
        
    } catch {
        print("Login failed: \(error.localizedDescription)")
    }
}

*Note: Firebase requires passwords to be at least 6 characters long by default. If it is shorter, the do-catch block will catch a specific Firebase error!*

6. Managing the Session (The "Magic" Switch)

When a user logs in, they expect to stay logged in even if they close the app. Firebase manages this session securely on the device automatically! However, we need our UI to know about it. We use the @Published broadcaster to track the current user. If the user exists, we show the Home Screen. If they are nil, we show the Login Screen!
swift
123456789101112131415161718192021
import FirebaseAuth

@MainActor
class SessionManager: ObservableObject {
    // This tracks if someone is logged in!
    @Published var currentUser: User?
    
    init() {
        // When the app launches, we ask Firebase: "Is someone currently logged in?"
        self.currentUser = Auth.auth().currentUser
    }
    
    func logout() {
        do {
            try Auth.auth().signOut()
            self.currentUser = nil // Instantly redraws the UI!
        } catch {
            print("Error signing out.")
        }
    }
}

7. Mini Project: The Protected Screen UI

Let's build the absolute root of our application. It acts as a traffic cop.
swift
123456789101112131415161718192021
import SwiftUI

struct RootView: View {
    // Instantiate our Session Manager
    @StateObject private var session = SessionManager()
    
    var body: some View {
        Group {
            // The Traffic Cop Logic!
            if session.currentUser != nil {
                // If a user exists, show the protected main app!
                MainAppDashboard()
            } else {
                // If they are nil, trap them on the login screen!
                LoginScreenView()
            }
        }
        // We inject the session into the environment so ANY screen can call session.logout()!
        .environmentObject(session)
    }
}

8. Common Mistakes

  • Logging In from Background Threads: If you execute the Firebase login function, and then attempt to immediately change a @Published property (like self.isLoggedIn = true) to swap the screens, you will trigger a Main Thread violation unless your ViewModel is explicitly marked with @MainActor.
  • Hardcoding Passwords: Never, ever hardcode testing credentials in your UI views. Always capture them dynamically via a SecureField two-way binding.

9. Best Practices

  • Security Rules Mapping: Once you have a Firebase UID (result.user.uid), you should use that exact UID as the document ID when saving their profile data in the Firestore database. This allows you to write a strict Firebase Security Rule: *"Only allow a user to edit this document if the document ID matches their Authentication UID."*

10. Exercises

  1. 1. Write the explicit Firebase Swift command required to log a user out of the application securely.
  1. 2. Explain how the SessionManager in Section 6 knows the user is logged in even after the app has been completely closed and reopened.

11. Coding Challenges

Challenge: Build the LoginScreenView UI mentioned in Section 7. Create two @State variables for email and password. Use a TextField (with .keyboardType(.emailAddress)) and a SecureField. Add a "Sign In" button that triggers a local print statement to verify the UI is bound correctly.

12. MCQ Quiz with Answers

Question 1

Which Firebase SDK package must be explicitly imported at the top of the Swift file to gain access to the Auth.auth().signIn() methodologies?

Question 2

When successfully executing Auth.auth().createUser(withEmail:password:), what uniquely identifying cryptographic string is generated and returned by Firebase, which developers use to tie database records to that specific human being?

13. Interview Questions

  • Q: Explain the immense architectural danger of rolling a custom authentication system (password hashing, salting, database storage) versus utilizing an enterprise BaaS solution like FirebaseAuth.
  • Q: Describe the concept of a "Session State". How does FirebaseAuth maintain persistent sessions across application terminations, and how can SwiftUI react to these state changes?
  • Q: In a production application, detail the mechanism by which the root UI (WindowGroup) acts as a router, dynamically swapping between an authentication flow and the main application dashboard based on the presence of a user token.

14. FAQs

Q: Can I let users log in with FaceID or Apple ID? A: Yes! Firebase Authentication fully supports "Sign in with Apple" (which is strictly required by Apple App Store guidelines if you offer social logins), as well as Google, Facebook, and Twitter logins. The SDK handles the complex OAuth token exchanges automatically.

15. Summary

In Chapter 23, we fortified our application by establishing strict digital identity. We navigated the Firebase Console to enable secure Email/Password pipelines, and integrated the robust FirebaseAuth SDK. We mastered asynchronous authentication flows, securely executing both createUser and signIn operations, while capturing the critical cryptographic UID. Finally, we engineered a persistent, reactive Session Manager, allowing the root SwiftUI architecture to dynamically barricade unauthenticated users from the core application experience.

16. Next Chapter Recommendation

Our app logic is complete, but it feels like a software program, not a physical phone app. We need to interact with the device's hardware. Proceed to Chapter 24: Notifications and Device Features.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·