Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/AuthServiceError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ public enum AuthServiceError: LocalizedError {
case invalidCredentials(String)
case signInFailed(underlying: Error)
case accountMergeConflict(context: AccountMergeConflictContext)
case invalidPhoneAuthenticationArguments(String)
case providerNotFound(String)
case multiFactorAuth(String)
case rootViewControllerNotFound(String)
case providerAuthenticationFailed(String)
case signInCancelled(String)

public var errorDescription: String? {
switch self {
Expand All @@ -54,16 +56,22 @@ public enum AuthServiceError: LocalizedError {
return description
case let .invalidCredentials(description):
return description
// Use when failed to sign-in with Firebase
case let .signInFailed(underlying: error):
return "Failed to sign in: \(error.localizedDescription)"
// Use when failed to sign-in with provider (e.g. Google, Facebook, etc.)
case let .providerAuthenticationFailed(description):
return description
case let .signInCancelled(description):
return description
case let .accountMergeConflict(context):
return context.errorDescription
case let .providerNotFound(description):
return description
case let .invalidPhoneAuthenticationArguments(description):
return description
case let .multiFactorAuth(description):
return description
case let .rootViewControllerNotFound(description):
return description
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ public final class PasswordPromptCoordinator {

func cancel() {
continuation?
.resume(throwing: AuthServiceError.reauthenticationRequired("Password entry cancelled"))
.resume(throwing: AuthServiceError
.signInCancelled("Password entry cancelled for Email provider"))
cleanup()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,6 @@ import FirebaseAuth
import FirebaseAuthSwiftUI
import SwiftUI

public enum FacebookProviderError: Error {
case signInCancelled(String)
case configurationInvalid(String)
case limitedLoginNonce(String)
case accessToken(String)
case authenticationToken(String)
}

public class FacebookProviderSwift: AuthProviderSwift, DeleteUserSwift {
let scopes: [String]
let providerId = "facebook.com"
Expand Down Expand Up @@ -60,8 +52,8 @@ public class FacebookProviderSwift: AuthProviderSwift, DeleteUserSwift {
)
}
}() else {
throw FacebookProviderError
.configurationInvalid("Failed to create Facebook login configuration")
throw AuthServiceError
.providerAuthenticationFailed("Failed to create Facebook login configuration")
}

let result = try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<
Expand All @@ -74,7 +66,8 @@ public class FacebookProviderSwift: AuthProviderSwift, DeleteUserSwift {
switch result {
case .cancelled:
continuation
.resume(throwing: FacebookProviderError.signInCancelled("User cancelled sign-in"))
.resume(throwing: AuthServiceError
.signInCancelled("User cancelled sign-in for Facebook"))
case let .failed(error):
continuation.resume(throwing: error)
case .success:
Expand All @@ -97,8 +90,8 @@ public class FacebookProviderSwift: AuthProviderSwift, DeleteUserSwift {

return credential
} else {
throw FacebookProviderError
.accessToken(
throw AuthServiceError
.providerAuthenticationFailed(
"Access token has expired or not available. Please sign-in with Facebook before attempting to create a Facebook provider credential"
)
}
Expand All @@ -107,16 +100,18 @@ public class FacebookProviderSwift: AuthProviderSwift, DeleteUserSwift {
private func limitedLogin() throws -> AuthCredential {
if let idToken = AuthenticationToken.current {
guard let nonce = rawNonce else {
throw FacebookProviderError
.limitedLoginNonce("`rawNonce` has not been generated for Facebook limited login")
throw AuthServiceError
.providerAuthenticationFailed(
"`rawNonce` has not been generated for Facebook limited login"
)
}
let credential = OAuthProvider.credential(withProviderID: providerId,
idToken: idToken.tokenString,
rawNonce: nonce)
return credential
} else {
throw FacebookProviderError
.authenticationToken(
throw AuthServiceError
.providerAuthenticationFailed(
"Authentication is not available. Please sign-in with Facebook before attempting to create a Facebook provider credential"
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,7 @@ extension SignInWithFacebookButton: View {
VStack {
Button(action: {
Task {
do {
try await authService.signIn(facebookProvider)
} catch {
switch error {
case FacebookProviderError.signInCancelled:
showCanceledAlert = true
default:
// Error already handled by AuthService
break
}
}
try? await authService.signIn(facebookProvider)
}
}) {
HStack {
Expand Down Expand Up @@ -113,12 +103,6 @@ extension SignInWithFacebookButton: View {
.toggleStyle(SwitchToggleStyle(tint: .green))
}
}
.alert(isPresented: $showCanceledAlert) {
Alert(
title: Text(authService.string.facebookLoginCancelledLabel),
dismissButton: .default(Text(authService.string.okButtonLabel))
)
}
.alert(isPresented: $showUserTrackingAlert) {
Alert(
title: Text(authService.string.authorizeUserTrackingLabel),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@ import GoogleSignIn
import GoogleSignInSwift
import SwiftUI

public enum GoogleProviderError: Error {
case rootViewControllerNotFound(String)
case authenticationToken(String)
case user(String)
}

public class GoogleProviderSwift: AuthProviderSwift, DeleteUserSwift {
let scopes: [String]
let clientID: String
Expand All @@ -42,7 +36,7 @@ public class GoogleProviderSwift: AuthProviderSwift, DeleteUserSwift {
@MainActor public func createAuthCredential() async throws -> AuthCredential {
guard let presentingViewController = await (UIApplication.shared.connectedScenes
.first as? UIWindowScene)?.windows.first?.rootViewController else {
throw GoogleProviderError
throw AuthServiceError
.rootViewControllerNotFound(
"Root View controller is not available to present Google sign-in View."
)
Expand All @@ -63,7 +57,8 @@ public class GoogleProviderSwift: AuthProviderSwift, DeleteUserSwift {
guard let user = result?.user,
let idToken = user.idToken?.tokenString else {
continuation
.resume(throwing: GoogleProviderError.user("Failed to retrieve user or idToken."))
.resume(throwing: AuthServiceError
.providerAuthenticationFailed("Failed to retrieve user or idToken."))
return
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public class OAuthProviderSwift: AuthProviderSwift, DeleteUserSwift {
self.buttonBackgroundColor = buttonBackgroundColor
self.buttonForegroundColor = buttonForegroundColor
}

/// Convenience initializer using SF Symbol
/// - Parameters:
/// - providerId: The OAuth provider ID (e.g., "github.com", "microsoft.com")
Expand Down Expand Up @@ -132,6 +133,7 @@ public class OAuthProviderAuthUI: AuthProviderUI {
}
return oauthProvider.providerId
}

@MainActor public func authButton() -> AnyView {
AnyView(GenericOAuthButton(provider: provider))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class PhoneProviderSwift: PhoneAuthProviderSwift {
guard let presentingViewController = await (UIApplication.shared.connectedScenes
.first as? UIWindowScene)?.windows.first?.rootViewController else {
throw AuthServiceError
.invalidPhoneAuthenticationArguments(
.rootViewControllerNotFound(
"Root View controller is not available to present Phone auth View."
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,8 @@ extension PhoneAuthView: View {
HStack {
Spacer()
Button(action: {
completion(.failure(NSError(
domain: "PhoneAuthError",
code: -1,
userInfo: [NSLocalizedDescriptionKey: "User cancelled"]
)))
completion(.failure(AuthServiceError
.signInCancelled("User cancelled sign-in for Phone")))
dismiss()
}) {
Image(systemName: "xmark.circle.fill")
Expand Down
Loading