Final (21)
회원 탈퇴시 재인증 문제 해결
개요
이번 작업에서는 Apple/Google 로그인 및 로그아웃, 탈퇴 관련 로직을 다음과 같은 목표로 수정 및 보완했다:
- Apple 로그인 시 불필요한 fullName 처리 제거
- Google 로그인 시 토큰 저장 기능 추가
- Google 탈퇴 로직에서 Firebase 재인증 처리 구현 ← 핵심!
- 중복 코드 및 콘솔 출력 최소화
변경 내역 상세 정리
1. Apple 로그인 (saveApple
)
문제
- 기존에는
fullName
을 credential 생성 시 항상 전달했음 - 하지만
appleCredential.fullName
은 최초 로그인 이후 거의 항상nil
→ 충돌 가능성
수정 코드
OAuthProvider.appleCredential(withIDToken: tokenString, rawNonce: nonce, fullName: nil)
fullName
을 명시적으로 nil 처리하여 credential 안정성 확보- 콘솔에 노출되던 JWT, 토큰 관련
print
제거
2. Google 로그인 시 토큰 저장
목적
탈퇴 시 Firebase의 reauthenticate
요구에 대응하기 위해
Google 로그인 성공 시 ID Token과 Access Token을 저장한다.
예시 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
googleSignIn(result: GIDSignInResult, completion: @escaping (Result<AuthDataResult?, Error>) -> Void) {
let idToken = result.user.idToken?.tokenString ?? ""
let accessToken = result.user.accessToken.tokenString
if idToken.isEmpty {
completion(.failure(NSError(domain: "GoogleSignIn", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unable to fetch Google tokens"])))
return
}
let credential = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: accessToken)
Auth.auth().signIn(with: credential) { result, error in
if let error = error {
completion(.failure(error))
} else {
UserDefaults.standard.set(idToken, forKey: "googleIDToken")
UserDefaults.standard.set(accessToken, forKey: "googleAccessToken")
completion(.success(result))
}
}
}
- 토큰 저장 키:
"googleIDToken"
,"googleAccessToken"
3. Google 탈퇴 시 Firebase 재인증 처리 ← 핵심
문제
Google 사용자가 탈퇴할 때, 재인증이 없다면 다음 에러가 발생:
auth/requires-recent-login
→ Firebase 보안 정책: 사용자 삭제 전에 최근 인증 필요
해결 전략
- 로그인 시 저장한 토큰을 사용하여 credential 생성
reauthenticate(with:)
실행- 성공하면 실제 사용자 삭제 수행
예시 코드 (SignManager 내부)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
deleteCurrentUser(completion: @escaping (Result<Void, Error>) -> Void) {
guard let user = Auth.auth().currentUser else {
completion(.failure(...))
return
}
for provider in user.providerData {
switch provider.providerID {
case "google.com":
var credential: AuthCredential?
if let idToken = UserDefaults.standard.string(forKey: "googleIDToken"),
let accessToken = UserDefaults.standard.string(forKey: "googleAccessToken") {
credential = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: accessToken)
}
guard let authCredential = credential else {
completion(.failure(...))
return
}
user.reauthenticate(with: authCredential) { _, error in
if let error = error {
completion(.failure(error))
} else {
self.performDelete(user: user, completion: completion)
}
}
default:
break
}
}
}
결과
- Firebase의 재인증 요구 충족
- 실제 탈퇴 가능
- 사용자 경험 개선 (더 이상 실패 메시지로 막히지 않음)
4. 공통 삭제 로직 분리 (performDelete
)
Google과 Apple의 삭제 로직을 중복 없이 관리하기 위해 다음처럼 공통 처리 분리:
performDelete(user: FirebaseAuth.User, completion: @escaping (Result<Void, Error>) -> Void)
→ 내부에서 providerID에 따라 분기 처리 후 삭제
해결된 문제 요약
문제 | 이전 상태 | 해결 방법 |
---|---|---|
Apple 로그인 시 fullName 충돌 가능성 | fullName 전달 | nil로 고정 |
Google 탈퇴 시 재인증 오류 (requires-recent-login ) | 재인증 생략 → 탈퇴 실패 | 저장된 토큰으로 reauthenticate 후 삭제 |
민감한 콘솔 로그 | JWT/토큰 print 노출 | 디버깅용 print 제거 |
탈퇴 로직 중복 | provider마다 중복 코드 | performDelete로 통합 관리 |
결론
이번 수정은 Firebase 인증을 사용하는 앱에서 발생할 수 있는 실질적인 문제들을 해결한 중요한 리팩토링이었다.
특히 Google 탈퇴 시 발생하는 requires-recent-login
문제는 직접 경험해보지 않으면 원인 파악이 어려운 문제였다.
이를 해결하기 위해:
- 로그인 시 토큰 저장
- 탈퇴 시 재인증
- 공통 삭제 흐름 분리
까지 체계적으로 구성되었으며, 다른 Firebase 기반 앱에서도 유용하게 재사용할 수 있는 구조이다.
이 문제로 당시 지피티를 이용해도 직접적인 해결이 어려워 애를 먹었기 때문에, 이 문서가 같은 문제를 겪는 개발자에게 큰 도움이 될 수 있다.