Skip to content

Commit 097dc18

Browse files
refactor: passwordPrompt should be on emailprovider, not auth service
1 parent 77d6ed9 commit 097dc18

File tree

4 files changed

+54
-10
lines changed

4 files changed

+54
-10
lines changed

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Services/AuthService.swift

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,13 @@ public final class AuthService {
132132
public var authenticationState: AuthenticationState = .unauthenticated
133133
public var authenticationFlow: AuthenticationFlow = .signIn
134134

135-
public var passwordPrompt: PasswordPromptCoordinator = .init()
136135
private var currentMFAResolver: MultiFactorResolver?
137136

138137
// MARK: - Provider APIs
139138

140139
private var listenerManager: AuthListenerManager?
141140

141+
internal private(set) var emailProvider: EmailProviderSwift?
142142
var emailSignInEnabled = false
143143
private var emailSignInCallback: (() -> Void)?
144144

@@ -316,14 +316,18 @@ public extension AuthService {
316316

317317
public extension AuthService {
318318
/// Enable email sign-in with default behavior (navigates to email link view)
319-
func withEmailSignIn() -> AuthService {
320-
return withEmailSignIn { [weak self] in
319+
func withEmailSignIn(_ provider: EmailProviderSwift? = nil) -> AuthService {
320+
return withEmailSignIn(provider) { [weak self] in
321321
self?.navigator.push(.emailLink)
322322
}
323323
}
324324

325325
/// Enable email sign-in with custom callback
326-
func withEmailSignIn(onTap: @escaping () -> Void) -> AuthService {
326+
func withEmailSignIn(
327+
_ provider: EmailProviderSwift? = nil,
328+
onTap: @escaping () -> Void
329+
) -> AuthService {
330+
emailProvider = provider ?? EmailProviderSwift()
327331
emailSignInEnabled = true
328332
emailSignInCallback = onTap
329333
return self
@@ -746,8 +750,14 @@ public extension AuthService {
746750
guard let email = user.email else {
747751
throw AuthServiceError.invalidCredentials("User does not have an email address")
748752
}
749-
let password = try await passwordPrompt.confirmPassword()
750-
let credential = EmailAuthProvider.credential(withEmail: email, password: password)
753+
754+
guard let emailProvider = emailProvider else {
755+
throw AuthServiceError.providerNotFound(
756+
"Email provider not configured. Call withEmailSignIn() first."
757+
)
758+
}
759+
760+
let credential = try await emailProvider.createReauthCredential(email: email)
751761
_ = try await user.reauthenticate(with: credential)
752762
} else if providerId == PhoneAuthProviderID {
753763
// Phone auth requires manual reauthentication via sign out and sign in otherwise it will take
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import FirebaseAuth
16+
17+
/// Email/Password authentication provider
18+
/// This provider is special and doesn't render in the button list
19+
@MainActor
20+
public class EmailProviderSwift: AuthProviderSwift {
21+
public let passwordPrompt: PasswordPromptCoordinator
22+
public let providerId = EmailAuthProviderID
23+
24+
public init(passwordPrompt: PasswordPromptCoordinator = .init()) {
25+
self.passwordPrompt = passwordPrompt
26+
}
27+
28+
/// Create credential for reauthentication
29+
func createReauthCredential(email: String) async throws -> AuthCredential {
30+
let password = try await passwordPrompt.confirmPassword()
31+
return EmailAuthProvider.credential(withEmail: email, password: password)
32+
}
33+
}
34+

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/AuthPickerView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public struct AuthPickerView<Content: View> {
3333
extension AuthPickerView: View {
3434
public var body: some View {
3535
@Bindable var authService = authService
36-
@Bindable var passwordPrompt = authService.passwordPrompt
36+
@Bindable var passwordPrompt = authService.emailProvider?.passwordPrompt ?? PasswordPromptCoordinator()
3737
content()
3838
.sheet(isPresented: $authService.isPresented) {
3939
@Bindable var navigator = authService.navigator
@@ -82,7 +82,7 @@ extension AuthPickerView: View {
8282
}
8383
// Centralized password prompt sheet to prevent conflicts
8484
.sheet(isPresented: $passwordPrompt.isPromptingPassword) {
85-
PasswordPromptSheet(coordinator: authService.passwordPrompt)
85+
PasswordPromptSheet(coordinator: passwordPrompt)
8686
}
8787
}
8888

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Views/UpdatePasswordView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public struct UpdatePasswordView {
5353

5454
extension UpdatePasswordView: View {
5555
public var body: some View {
56-
@Bindable var passwordPrompt = authService.passwordPrompt
56+
@Bindable var passwordPrompt = authService.emailProvider?.passwordPrompt ?? PasswordPromptCoordinator()
5757
VStack(spacing: 24) {
5858
AuthTextField(
5959
text: $password,
@@ -116,7 +116,7 @@ extension UpdatePasswordView: View {
116116
Text("Your password has been successfully updated.")
117117
}
118118
.sheet(isPresented: $passwordPrompt.isPromptingPassword) {
119-
PasswordPromptSheet(coordinator: authService.passwordPrompt)
119+
PasswordPromptSheet(coordinator: passwordPrompt)
120120
}
121121
}
122122
}

0 commit comments

Comments
 (0)