Skip to content

Commit 1983e73

Browse files
auto link accounts
1 parent e21a3fc commit 1983e73

3 files changed

Lines changed: 42 additions & 22 deletions

File tree

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Services/AuthService.swift

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,6 @@ public protocol PhoneAuthProviderProtocol {
1414
@MainActor func verifyPhoneNumber(phoneNumber: String) async throws -> String
1515
}
1616

17-
public enum AuthenticationProvider {
18-
case email
19-
case google
20-
}
21-
22-
public enum AuthenticationOperationType: String {
23-
case signIn
24-
case signUp
25-
case deleteAccount
26-
}
27-
2817
public enum AuthenticationState {
2918
case unauthenticated
3019
case authenticating
@@ -153,17 +142,32 @@ public final class AuthService {
153142
updateAuthenticationState()
154143
}
155144

156-
public func signIn(with credentials: AuthCredential) async throws {
145+
public func linkAccounts(credentials credentials: AuthCredential) async throws {
157146
authenticationState = .authenticating
158147
do {
159-
try await auth.signIn(with: credentials)
148+
try await currentUser?.link(with: credentials)
160149
updateAuthenticationState()
161150
} catch {
162151
authenticationState = .unauthenticated
163152
throw error
164153
}
165154
}
166155

156+
public func signIn(credentials credentials: AuthCredential) async throws {
157+
authenticationState = .authenticating
158+
if currentUser?.isAnonymous == true, configuration.shouldAutoUpgradeAnonymousUsers {
159+
try await linkAccounts(credentials: credentials)
160+
} else {
161+
do {
162+
try await auth.signIn(with: credentials)
163+
updateAuthenticationState()
164+
} catch {
165+
authenticationState = .unauthenticated
166+
throw error
167+
}
168+
}
169+
}
170+
167171
func sendEmailVerification() async throws {
168172
if currentUser != nil {
169173
do {
@@ -181,11 +185,12 @@ public final class AuthService {
181185
public extension AuthService {
182186
func signIn(withEmail email: String, password: String) async throws {
183187
let credential = EmailAuthProvider.credential(withEmail: email, password: password)
184-
try await auth.signIn(with: credential)
188+
try await signIn(credentials: credential)
185189
}
186190

187191
func createUser(withEmail email: String, password: String) async throws {
188192
authenticationState = .authenticating
193+
189194
do {
190195
try await auth.createUser(withEmail: email, password: password)
191196
updateAuthenticationState()
@@ -252,7 +257,7 @@ public extension AuthService {
252257
}
253258
let credential = try await safeGoogleProvider.signInWithGoogle(clientID: clientID)
254259

255-
try await signIn(with: credential)
260+
try await signIn(credentials: credential)
256261
updateAuthenticationState()
257262
} catch {
258263
authenticationState = .unauthenticated
@@ -269,7 +274,7 @@ public extension AuthService {
269274
do {
270275
let credential = try await safeFacebookProvider
271276
.signInWithFacebook(isLimitedLogin: limitedLogin)
272-
try await signIn(with: credential)
277+
try await signIn(credentials: credential)
273278
updateAuthenticationState()
274279
} catch {
275280
authenticationState = .unauthenticated
@@ -290,7 +295,7 @@ public extension AuthService {
290295
do {
291296
let credential = PhoneAuthProvider.provider()
292297
.credential(withVerificationID: verificationID, verificationCode: verificationCode)
293-
try await signIn(with: credential)
298+
try await signIn(credentials: credential)
294299
updateAuthenticationState()
295300
} catch {
296301
authenticationState = .unauthenticated

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/EmailAuthView.swift

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//
55
// Created by Russell Wheatley on 20/03/2025.
66
//
7+
import FirebaseAuth
78
import SwiftUI
89

910
private enum FocusableField: Hashable {
@@ -36,10 +37,19 @@ public struct EmailAuthView {
3637
private func signInWithEmailPassword() async {
3738
do {
3839
try await authService.signIn(withEmail: email, password: password)
39-
} catch {
40-
errorMessage = authService.string.localizedErrorMessage(
41-
for: error
42-
)
40+
} catch let error as NSError {
41+
switch AuthErrorCode(rawValue: error.code) {
42+
case .credentialAlreadyInUse:
43+
// TODO: - how are we handling this?
44+
if let updatedCredential = error
45+
.userInfo[AuthErrorUserInfoUpdatedCredentialKey] as? AuthCredential {
46+
// user ought to merge accounts on their backend here
47+
}
48+
default:
49+
errorMessage = authService.string.localizedErrorMessage(
50+
for: error
51+
)
52+
}
4353
}
4454
}
4555

samples/swiftui/FirebaseSwiftUIExample/FirebaseSwiftUIExample/FirebaseSwiftUIExampleApp.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,18 @@ struct ContentView: View {
7878
let authService: AuthService
7979

8080
init() {
81+
// Auth.auth().signInAnonymously()
82+
8183
let actionCodeSettings = ActionCodeSettings()
8284
actionCodeSettings.handleCodeInApp = true
8385
actionCodeSettings
8486
.url = URL(string: "https://flutterfire-e2e-tests.firebaseapp.com")
8587
actionCodeSettings.linkDomain = "flutterfire-e2e-tests.firebaseapp.com"
8688
actionCodeSettings.setIOSBundleID(Bundle.main.bundleIdentifier!)
87-
let configuration = AuthConfiguration(emailLinkSignInActionCodeSettings: actionCodeSettings)
89+
let configuration = AuthConfiguration(
90+
shouldAutoUpgradeAnonymousUsers: true,
91+
emailLinkSignInActionCodeSettings: actionCodeSettings
92+
)
8893
let facebookProvider = FacebookProviderSwift()
8994
let phoneAuthProvider = PhoneAuthProviderSwift()
9095
authService = AuthService(

0 commit comments

Comments
 (0)