728x90
SMALL
1️⃣ SocialAuthCoordinator를 만든 이유 (왜 이 클래스가 필요했나)
소셜 로그인은 한 단계짜리 작업이 아니다.
카카오 로그인을 예로 들면 실제 흐름은 이거야:
- Kakao SDK → accessToken 발급
- 서버(Firebase Functions) → accessToken 검증
- 서버 → Firebase Custom Token 생성
- 앱 → Firebase Auth signIn
- Firebase Auth → 인증 상태 변경
👉 “로그인”이라는 말 하나에 4~5개의 책임이 섞여 있음
❌ Coordinator가 없을 때의 문제
만약 이걸 AuthService 하나에 몰아넣으면:
- Kakao / Naver SDK를 알아야 하고
- Firebase Functions 호출을 알아야 하고
- Custom Token 구조를 알아야 하고
- Firebase Auth API도 알아야 함
즉,
AuthService가 ‘모든 인증 세계관’을 다 아는 God Object가 됨
이 상태가 되면:
- 테스트 불가
- 교체 불가
- provider 추가 시 코드 폭발
2️⃣ “그래서 왜 Coordinator인가?”
Coordinator의 핵심 역할은 딱 하나야
여러 단계를 “하나의 유스케이스”로 묶어주는 것
SocialAuthCoordinator는:
- Kakao SDK ❌ (여기서 안 다룸)
- UI ❌
- 화면 전환 ❌
오직 이것만 함 👇
“소셜 accessToken → Firebase 인증 상태”로 변환
그래서 이름도 정확히 SocialAuthCoordinator

3️⃣ 로직 구조에서의 위치 (중요)
현재 구조를 한 줄로 요약하면 이거야:
UI / SDK
↓
AuthService
↓
SocialAuthCoordinator
↓
Firebase Functions + Firebase Auth
여기서 각 계층의 책임을 보면 👇
| 계층 | 책임 |
| KakaoAuthHandler | SDK 로그인, accessToken 획득 |
| AuthService | 로그인 진입점, provider 분기 |
| SocialAuthCoordinator | 소셜 인증 → Firebase 인증 변환 |
| FirebaseFunctionsService | 서버 호출 |
| FirebaseAuthService | Firebase Auth signIn |
📌 Coordinator는 ‘경계 변환기’ 역할
→ 외부 인증 세계 → Firebase 인증 세계
4️⃣ 왜 async/await를 여기서는 써도 되는가?
이 포인트도 중요해.
SocialAuthCoordinator의 특징
- UI 호출 ❌
- 외부 앱 이동 ❌
- SceneDelegate ❌
- 순수 비동기 작업만 있음
하는 일은 전부:
- 네트워크
- 서버
- Firebase SDK
👉 100% 앱 내부 비동기 작업
그래서 여기서는:
func signIn(...) async throws
이게 가장 자연스럽고, 가장 안전한 형태.
5️⃣ “AuthService가 아니라 왜 Coordinator인가?”
이 질문 정말 중요하다.
AuthService의 역할
- “로그인을 시작한다”
- “어떤 provider인지 결정한다”
- “SDK 핸들러를 선택한다”
👉 진입점 (Facade)
SocialAuthCoordinator의 역할
- “이 accessToken을 Firebase 인증으로 바꾼다”
👉 유스케이스 실행자
즉,
AuthService는 ‘무엇을 할지’,
Coordinator는 ‘어떻게 완료할지’
이 분리가 되어 있어서 구조가 깨끗한 거야.
📖 이 클래스를 만들어둔 진짜 가치
이 구조 덕분에 나중에:
- ✅ Naver 추가
- ✅ Google Custom Token
- ✅ Server 인증 정책 변경
- ✅ Firebase → 다른 Auth로 교체
전부 Coordinator 내부만 수정하면 돼.
AuthService / ViewModel / UI는 그대로.
▶️ 전체코드
import Foundation
// MARK: - SocialAuthCoordinator
/// 소셜 로그인(Kakao, Naver)을 Firebase 인증으로 변환하는 Coordinator 구현체입니다.
///
/// 📌 이 클래스의 핵심 목적은
/// "소셜 인증 세계"와 "Firebase 인증 세계"를 분리하는 것입니다.
///
/// 책임:
/// 1. 소셜 SDK에서 발급된 accessToken을 입력으로 받습니다.
/// 2. Firebase Functions를 통해 서버에서 Custom Token을 발급받습니다.
/// 3. 발급된 Custom Token으로 Firebase Auth 인증을 완료합니다.
///
/// ❗️이 클래스는 UI, SDK 호출, 화면 전환을 전혀 알지 않습니다.
/// 오직 "인증 변환(use case)"만 담당합니다.
///
/// AuthService는 이 Coordinator에만 의존하며,
/// Firebase Functions, Custom Token, Firebase Auth의
/// 구체적인 구현 디테일을 알 필요가 없습니다.
///
/// 👉 결과적으로
/// - AuthService는 단순해지고
/// - provider 확장이 쉬워지며
/// - 인증 로직 테스트가 가능해집니다.
final class SocialAuthCoordinator: SocialAuthCoordinating {
// MARK: - Dependencies
/// Firebase Functions 호출을 담당하는 인터페이스
private let functionsService: FirebaseFunctionsServicing
/// Firebase Auth 인증을 담당하는 인터페이스
private let authService: FirebaseAuthServicing
// MARK: - Initializer
/// SocialAuthCoordinator를 초기화합니다.
///
/// - Parameters:
/// - functionsService: Firebase Functions 호출을 담당하는 서비스
/// - authService: Firebase Auth 인증을 담당하는 서비스
init(
functionsService: FirebaseFunctionsServicing,
authService: FirebaseAuthServicing
) {
self.functionsService = functionsService
self.authService = authService
}
// MARK: - SocialAuthCoordinating
/// 소셜 로그인 accessToken을 이용해 Firebase 인증을 수행합니다.
///
/// 이 메서드는 다음 순서로 동작합니다:
/// 1. 전달받은 provider가 지원되는 소셜 로그인인지 검증합니다.
/// 2. Firebase Functions를 호출하여 Custom Token을 요청합니다.
/// 3. 응답에서 Custom Token을 파싱합니다.
/// 4. Firebase Auth에 Custom Token으로 로그인합니다.
///
/// - Parameters:
/// - accessToken: Kakao / Naver SDK에서 발급된 accessToken
/// - provider: 소셜 로그인 제공자 타입
///
/// - Throws:
/// - AuthError.unsupportedProvider: 지원하지 않는 provider인 경우
/// - AuthError.invalidCustomToken: Custom Token 파싱 실패
/// - Firebase 관련 에러
func signIn(
with accessToken: String,
provider: SocialLoginProvider
) async throws {
// 1️⃣ 지원 Provider 검증
try validate(provider)
// 2️⃣ Firebase Functions 호출
let response = try await functionsService.requestCustomToken(
accessToken: accessToken,
provider: provider
)
// 3️⃣ Custom Token 파싱
guard let customToken = response.customToken else {
throw AuthError.invalidCustomToken
}
// 4️⃣ Firebase Auth 로그인
try await authService.signIn(withCustomToken: customToken)
}
}
// MARK: - Private Helpers
private extension SocialAuthCoordinator {
/// 지원 가능한 소셜 로그인 Provider인지 검증합니다.
///
/// - Parameter provider: 소셜 로그인 제공자
/// - Throws: AuthError.unsupportedProvider
func validate(_ provider: SocialLoginProvider) throws {
switch provider {
case .kakao, .naver:
return
default:
throw AuthError.unsupportedProvider
}
}
}728x90
LIST
'PulseBoard' 카테고리의 다른 글
| 🔐 iOS 네이버 로그인 키 관리 방법 (xcconfig + Info.plist + ClientConfiguration) (0) | 2025.12.30 |
|---|---|
| 🤔 async, await VC CompletionHandler 언제 써야하나?(KakaoAuthHandler) (0) | 2025.12.28 |
| 🎫 KakaoAuthHandler 는 왜 async/await를 버리고 completion 기반으로 되돌렸나? (0) | 2025.12.28 |
| Firebase Functions + Kakao 로그인 문제 해결 정리 (0) | 2025.12.27 |
| 🤔 카카오, 네이버 로그인 - accessToken 처리 방향 (1) | 2025.12.26 |