[Xcode/Swift] GPT先生と学ぶFirebase(Authentication編) No.1

とりあえずログインできればOKの実装はBAD❌

今どきのアプリは、ユーザー認証のUXと安全性が命
この章では以下の3つの認証方法をざっくり学んでいきます:

  • メール / パスワード認証
  • OAuth認証(Google / Apple / GitHub)
  • 匿名認証 → 既存アカウントへ統合(アカウントアップグレード)

Firebaseの初期セットアップはできている前提で進めます、まだここが完了していない場合は以下を参考に。

[Xcode/Swift] GPT先生と学ぶFirebase(導入、概念編) No.0

メール / パスワード認証

Firebase Console側で、メール/パスワード認証を許可しておく。

1-1. まずは動くコードを作る(SwiftUI × FirebaseAuth)

import SwiftUI
import FirebaseAuth

struct AuthView: View {
    @State private var email = ""
    @State private var password = ""
    @State private var user: User?
    @State private var errorMessage = ""

    var body: some View {
        VStack(spacing: 16) {
            if let user = user {
                Text("Welcome、\(user.email ?? "User")")
            } else {
                TextField("Email", text: $email)
                    .autocapitalization(.none)
                    .textFieldStyle(.roundedBorder)

                SecureField("Password", text: $password)
                    .textFieldStyle(.roundedBorder)

                Button("ログイン") {
                    signIn()
                }

                Button("新規登録") {
                    signUp()
                }

                if !errorMessage.isEmpty {
                    Text(errorMessage).foregroundColor(.red)
                }
            }
        }
        .padding()
    }

    private func signIn() {
        // メール認証
        Auth.auth().signIn(withEmail: email, password: password) { result, error in
            if let error = error {
                errorMessage = error.localizedDescription
            } else {
                user = result?.user
                errorMessage = ""
            }
        }
    }

    private func signUp() {
        // メールで新規ユーザ登録
        Auth.auth().createUser(withEmail: email, password: password) { result, error in
            if let error = error {
                errorMessage = error.localizedDescription
            } else {
                user = result?.user
                errorMessage = ""
            }
        }
    }
}
  • ログイン & 新規登録が動くこと
  • エラーが出たら画面に表示されること

1-2. 応用編:実戦でのグッドプラクティス

実戦では、Firebaseの直接呼び出しはViewから分離し、
ViewModelUseCaseRepository のような構造にして、DIで注入するのがGood。
※小規模アプリなら ViewModel に閉じてもOKだが、拡張性・テスト性を考えると分離がベター。

UIは .task で非同期呼び出しに切り替える。

@MainActor
class AuthViewModel: ObservableObject {
    @Published var user: User?
    @Published var errorMessage = ""

    func signIn(email: String, password: String) async {
        do {
            let result = try await Auth.auth().signIn(withEmail: email, password: password)
            user = result.user
            errorMessage = ""
        } catch {
            errorMessage = error.localizedDescription
        }
    }

    func signUp(email: String, password: String) async {
        do {
            let result = try await Auth.auth().createUser(withEmail: email, password: password)
            user = result.user
            errorMessage = ""
        } catch {
            errorMessage = error.localizedDescription
        }
    }
}

1-3. Tips & まとめ

  • パスワードは最低6文字以上じゃないと怒られる
  • Firebase Consoleで Email/Password認証を有効化 するの忘れがち
  • ユーザー情報は Auth.auth().currentUser で取得できる
  • user.isEmailVerified で認証済みかチェック可能(メール認証機能は別途)

OAuth認証(Google / Apple / GitHub)

今回はSign in with Appleの入口だけ

2-1. 準備(Firebase Console)

  • 対応したいプロバイダを有効化
  • Google → OAuthクライアントID設定
  • Apple → Sign In with Apple の設定(EntitlementとBundle ID)
  • GitHub → Client ID / Secretの登録

Sign in with Appleは、Apple Developer Program(年額 12,980円 / $99)への登録が必須です、注意。

機能無料アカウント有料アカウント
Firebase連携・テスト
Capability追加(Sign In With Apple)
実機ビルド + Apple認証テスト
App Storeへの公開

2-2. 実装の概要(Sign in with Apple 例)

Sign in with Appleはランダムnonce生成 & セキュリティ設定が必要

import AuthenticationServices
import FirebaseAuth

func handleAppleLogin(credential: ASAuthorizationAppleIDCredential) {
    guard let token = credential.identityToken,
          let idTokenString = String(data: token, encoding: .utf8) else {
        return
    }

    let firebaseCredential = OAuthProvider.credential(withProviderID: "apple.com",
                                                       idToken: idTokenString,
                                                       rawNonce: nonce)

    Auth.auth().signIn(with: firebaseCredential) { result, error in
        // Sign In結果の処理分岐
    }
}

匿名認証 → アップグレード

Email & Passwordの面倒な手続きなしで、すぐに機能を使えるようにする等の時に便利な認証方法

3-1. 匿名でログイン

Auth.auth().signInAnonymously { result, error in
    if let user = result?.user {
        print("匿名ユーザーID: \(user.uid)")
    }
}

// Anonymous = 匿名

3-2. アップグレード(例:メール/パスワードに)

let credential = EmailAuthProvider.credential(withEmail: email, password: password)

Auth.auth().currentUser?.link(with: credential) { result, error in
    if let error = error {
        print("アップグレード失敗: \(error.localizedDescription)")
    } else {
        print("匿名アカウントが通常アカウントに変換完了!")
    }
}

// currentUserにcredential(email & password)を紐づけるという流れ

まとめ

  • Firebase Authはメール/パス/OAuth/匿名を柔軟に使い分けられる
  • 最初は最小構成で動かしつつ、ViewModelやアーキテクチャの整理を徐々にしていくのがGood
  • 匿名からアップグレードはMVP開発ではかなり有効な戦術!

次回は、Cloud Storageを使って画像/動画のアップロードやセキュリティルールを学びましょう。