Skip to content

Commit 52b92fb

Browse files
implementation for handling errors when auto upgrading anonymous user
1 parent 699c134 commit 52b92fb

File tree

2 files changed

+46
-4
lines changed

2 files changed

+46
-4
lines changed

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/AuthServiceError.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11

2+
import FirebaseAuth
23
import SwiftUI
34

5+
public struct AccountMergeConflictContext: LocalizedError {
6+
public let credential: AuthCredential
7+
public let underlyingError: Error
8+
public let message: String
9+
10+
public var errorDescription: String? {
11+
return message
12+
}
13+
}
14+
415
public enum AuthServiceError: LocalizedError {
516
case invalidEmailLink
617
case notConfiguredProvider(String)
@@ -9,6 +20,7 @@ public enum AuthServiceError: LocalizedError {
920
case reauthenticationRequired(String)
1021
case invalidCredentials(String)
1122
case signInFailed(underlying: Error)
23+
case accountMergeConflict(context: AccountMergeConflictContext)
1224

1325
public var errorDescription: String? {
1426
switch self {
@@ -26,6 +38,8 @@ public enum AuthServiceError: LocalizedError {
2638
return description
2739
case let .signInFailed(underlying: error):
2840
return "Failed to sign in: \(error.localizedDescription)"
41+
case let .accountMergeConflict(context):
42+
return context.errorDescription
2943
}
3044
}
3145
}

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Services/AuthService.swift

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ public final class AuthService {
141141
errorMessage = ""
142142
}
143143

144+
public var shouldHandleAnonymousUpgrade: Bool {
145+
currentUser?.isAnonymous == true && configuration.shouldAutoUpgradeAnonymousUsers
146+
}
147+
144148
public func signOut() async throws {
145149
do {
146150
try await auth.signOut()
@@ -167,15 +171,31 @@ public final class AuthService {
167171
}
168172
}
169173

174+
public func handleAutoUpgradeAnonymousUser(credentials credentials: AuthCredential) async throws {
175+
do {
176+
try await currentUser?.link(with: credentials)
177+
} catch let error as NSError {
178+
if error.code == AuthErrorCode.emailAlreadyInUse.rawValue {
179+
let context = AccountMergeConflictContext(
180+
credential: credentials,
181+
underlyingError: error,
182+
message: "Unable to merge accounts. Use the credential in the context to resolve the conflict."
183+
)
184+
throw AuthServiceError.accountMergeConflict(context: context)
185+
}
186+
throw error
187+
}
188+
}
189+
170190
public func signIn(credentials credentials: AuthCredential) async throws {
171191
authenticationState = .authenticating
172192
do {
173-
if currentUser?.isAnonymous == true, configuration.shouldAutoUpgradeAnonymousUsers {
174-
try await linkAccounts(credentials: credentials)
193+
if shouldHandleAnonymousUpgrade {
194+
try await handleAutoUpgradeAnonymousUser(credentials: credentials)
175195
} else {
176196
try await auth.signIn(with: credentials)
177-
updateAuthenticationState()
178197
}
198+
updateAuthenticationState()
179199
} catch {
180200
authenticationState = .unauthenticated
181201
errorMessage = string.localizedErrorMessage(
@@ -231,7 +251,13 @@ public extension AuthService {
231251
authenticationState = .authenticating
232252

233253
do {
234-
try await auth.createUser(withEmail: email, password: password)
254+
if shouldHandleAnonymousUpgrade {
255+
// TODO: - check this works. This is how it is done in previous implementation, but I wonder if this would fail
256+
let credential = EmailAuthProvider.credential(withEmail: email, password: password)
257+
try await handleAutoUpgradeAnonymousUser(credentials: credential)
258+
} else {
259+
try await auth.createUser(withEmail: email, password: password)
260+
}
235261
updateAuthenticationState()
236262
} catch {
237263
authenticationState = .unauthenticated
@@ -278,6 +304,8 @@ public extension AuthService {
278304
throw AuthServiceError.invalidEmailLink
279305
}
280306
let link = url.absoluteString
307+
// TODO: - get anonymous id here and check against current user before linking accounts
308+
// put anonymous uid on link and get it back: https://github.com/firebase/FirebaseUI-iOS/blob/main/FirebaseEmailAuthUI/Sources/FUIEmailAuth.m#L822
281309
if auth.isSignIn(withEmailLink: link) {
282310
let result = try await auth.signIn(withEmail: email, link: link)
283311
updateAuthenticationState()

0 commit comments

Comments
 (0)