Skip to content

Commit 1d8ff90

Browse files
Merge pull request #1258 from firebase/reauthenticate-google
2 parents cb015e4 + a2ea416 commit 1d8ff90

File tree

5 files changed

+105
-15
lines changed

5 files changed

+105
-15
lines changed

FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/Services/AuthService.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public protocol ExternalAuthProvider {
88

99
public protocol GoogleProviderAuthUIProtocol: ExternalAuthProvider {
1010
@MainActor func signInWithGoogle(clientID: String) async throws -> AuthCredential
11+
@MainActor func deleteUser(user: User) async throws
1112
}
1213

1314
public protocol FacebookProviderAuthUIProtocol: ExternalAuthProvider {
@@ -268,7 +269,7 @@ public final class AuthService {
268269
try await handleAutoUpgradeAnonymousUser(credentials: credentials)
269270
} else {
270271
let result = try await auth.signIn(with: credentials)
271-
signedInCredential = result.credential
272+
signedInCredential = result.credential ?? credentials
272273
}
273274
updateAuthenticationState()
274275
} catch {
@@ -301,11 +302,13 @@ public extension AuthService {
301302
func deleteUser() async throws {
302303
do {
303304
if let user = auth.currentUser, let providerId = signedInCredential?.provider {
304-
if providerId == "password" {
305+
if providerId == EmailAuthProviderID {
305306
let operation = EmailPasswordDeleteUserOperation(passwordPrompt: passwordPrompt)
306307
try await operation(on: user)
307-
} else if providerId == "facebook.com" {
308+
} else if providerId == FacebookAuthProviderID {
308309
try await facebookProvider.deleteUser(user: user)
310+
} else if providerId == GoogleAuthProviderID {
311+
try await googleProvider.deleteUser(user: user)
309312
}
310313
}
311314

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//
2+
// AccountService+Google.swift
3+
// FirebaseUI
4+
//
5+
// Created by Russell Wheatley on 22/05/2025.
6+
//
7+
8+
//
9+
// AccountService+Facebook.swift
10+
// FirebaseUI
11+
//
12+
// Created by Russell Wheatley on 14/05/2025.
13+
//
14+
15+
@preconcurrency import FirebaseAuth
16+
import FirebaseAuthSwiftUI
17+
import Observation
18+
19+
protocol GoogleOperationReauthentication {
20+
var googleProvider: GoogleProviderAuthUI { get }
21+
}
22+
23+
extension GoogleOperationReauthentication {
24+
@MainActor func reauthenticate() async throws -> AuthenticationToken {
25+
guard let user = Auth.auth().currentUser else {
26+
throw AuthServiceError.reauthenticationRequired("No user currently signed-in")
27+
}
28+
29+
do {
30+
let credential = try await googleProvider
31+
.signInWithGoogle(clientID: googleProvider.clientID)
32+
try await user.reauthenticate(with: credential)
33+
34+
return .firebase("")
35+
} catch {
36+
throw AuthServiceError.signInFailed(underlying: error)
37+
}
38+
}
39+
}
40+
41+
@MainActor
42+
class GoogleDeleteUserOperation: AuthenticatedOperation,
43+
@preconcurrency GoogleOperationReauthentication {
44+
let googleProvider: GoogleProviderAuthUI
45+
init(googleProvider: GoogleProviderAuthUI) {
46+
self.googleProvider = googleProvider
47+
}
48+
49+
func callAsFunction(on user: User) async throws {
50+
try await callAsFunction(on: user) {
51+
try await user.delete()
52+
}
53+
}
54+
}

FirebaseSwiftUI/FirebaseGoogleSwiftUI/Sources/Services/GoogleProviderAuthUI.swift

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,20 @@ public class GoogleProviderAuthUI: @preconcurrency GoogleProviderAuthUIProtocol
2020
let scopes: [String]
2121
let shortName = "Google"
2222
let providerId = "google.com"
23-
let clientID: String
23+
public let clientID: String
2424
public init(scopes: [String]? = nil, clientID: String = FirebaseApp.app()!.options.clientID!) {
2525
self.scopes = scopes ?? kDefaultScopes
2626
self.clientID = clientID
2727
}
2828

2929
@MainActor public func authButton() -> AnyView {
30-
let customViewModel = GoogleSignInButtonViewModel(
31-
scheme: .light,
32-
style: .wide,
33-
state: .normal
34-
)
35-
return AnyView(GoogleSignInButton(viewModel: customViewModel) {
36-
Task {
37-
try await self.signInWithGoogle(clientID: self.clientID)
38-
}
39-
})
30+
// Moved to SignInWithGoogleButton so we could sign in via AuthService
31+
AnyView(SignInWithGoogleButton())
32+
}
33+
34+
public func deleteUser(user: User) async throws {
35+
let operation = GoogleDeleteUserOperation(googleProvider: self)
36+
try await operation(on: user)
4037
}
4138

4239
@MainActor public func signInWithGoogle(clientID: String) async throws -> AuthCredential {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//
2+
// SignInWithGoogleButton.swift
3+
// FirebaseUI
4+
//
5+
// Created by Russell Wheatley on 22/05/2025.
6+
//
7+
import FirebaseAuthSwiftUI
8+
import FirebaseCore
9+
import GoogleSignInSwift
10+
import SwiftUI
11+
12+
@MainActor
13+
public struct SignInWithGoogleButton {
14+
@Environment(AuthService.self) private var authService
15+
16+
let customViewModel = GoogleSignInButtonViewModel(
17+
scheme: .light,
18+
style: .wide,
19+
state: .normal
20+
)
21+
}
22+
23+
extension SignInWithGoogleButton: View {
24+
public var body: some View {
25+
GoogleSignInButton(viewModel: customViewModel) {
26+
Task {
27+
try await authService.signInWithGoogle()
28+
}
29+
}
30+
}
31+
}
32+
33+
#Preview {
34+
FirebaseOptions.dummyConfigurationForPreview()
35+
return SignInWithGoogleButton()
36+
.environment(AuthService())
37+
}

samples/swiftui/FirebaseSwiftUIExample/FirebaseSwiftUIExample/ContentView.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ struct ContentView: View {
2525
actionCodeSettings.linkDomain = "flutterfire-e2e-tests.firebaseapp.com"
2626
actionCodeSettings.setIOSBundleID(Bundle.main.bundleIdentifier!)
2727
let configuration = AuthConfiguration(
28-
shouldAutoUpgradeAnonymousUsers: true,
2928
tosUrl: URL(string: "https://example.com/tos"),
3029
privacyPolicyUrl: URL(string: "https://example.com/privacy"),
3130
emailLinkSignInActionCodeSettings: actionCodeSettings

0 commit comments

Comments
 (0)