@@ -706,43 +706,57 @@ public extension AuthService {
706706 currentUser = auth. currentUser
707707 }
708708
709- /// Reauthenticates the current user with their sign-in provider
710- /// - Throws: `AuthServiceError.phoneReauthenticationRequired` for phone auth users
711- /// - Throws: `AuthServiceError.providerNotFound` if provider is not configured
712- func reauthenticate( ) async throws {
709+ /// Reauthenticates with a simple provider (Google, Apple, Facebook, Twitter, etc.)
710+ /// - Parameter context: The reauth context from `simpleReauthenticationRequired` error
711+ /// - Throws: Error if reauthentication fails or provider is not found
712+ /// - Note: This only works for providers that can automatically obtain credentials.
713+ /// For email/phone, handle the flow externally and use `reauthenticate(with:)`
714+ public func reauthenticate( context: ReauthContext ) async throws {
713715 guard let user = currentUser else {
714716 throw AuthServiceError . noCurrentUser
715717 }
716-
717- // Get the provider from the token instead of stored credential
718+
719+ // Find the provider and get credential
720+ guard let matchingProvider = providers. first ( where: { $0. id == context. providerId } ) ,
721+ let credentialProvider = matchingProvider. provider as? CredentialAuthProviderSwift else {
722+ throw AuthServiceError . providerNotFound ( " No provider found for \( context. providerId) " )
723+ }
724+
725+ let credential = try await credentialProvider. createAuthCredential ( )
726+ try await user. reauthenticate ( with: credential)
727+ currentUser = auth. currentUser
728+ }
729+
730+ /// Reauthenticates with a pre-obtained credential
731+ /// Use this when you've handled getting the credential yourself (email/phone)
732+ /// - Parameter credential: The authentication credential to use for reauthentication
733+ /// - Throws: Error if reauthentication fails
734+ public func reauthenticate( with credential: AuthCredential ) async throws {
735+ guard let user = currentUser else {
736+ throw AuthServiceError . noCurrentUser
737+ }
738+ try await user. reauthenticate ( with: credential)
739+ currentUser = auth. currentUser
740+ }
741+
742+ /// Internal helper to create reauth context and throw appropriate error
743+ /// - Throws: Appropriate `AuthServiceError` based on the provider type
744+ private func requireReauthentication( ) async throws -> Never {
718745 let providerId = try await getCurrentSignInProvider ( )
719-
720- if providerId == EmailAuthProviderID {
721- guard let email = user. email else {
722- throw AuthServiceError . invalidCredentials ( " User does not have an email address " )
723- }
724-
725- guard let emailProvider = emailProvider else {
726- throw AuthServiceError . providerNotFound (
727- " Email provider not configured. Call withEmailSignIn() first. "
728- )
729- }
730-
731- let credential = try await emailProvider. createReauthCredential ( email: email)
732- try await user. reauthenticate ( with: credential)
733- } else if providerId == PhoneAuthProviderID {
734- guard let phoneNumber = user. phoneNumber else {
735- throw AuthServiceError . invalidCredentials ( " User does not have a phone number " )
736- }
737-
738- // Throw error with context for phone reauthentication
739- throw AuthServiceError . phoneReauthenticationRequired ( phoneNumber: phoneNumber)
740- } else if let matchingProvider = providers. first ( where: { $0. id == providerId } ) ,
741- let credentialProvider = matchingProvider. provider as? CredentialAuthProviderSwift {
742- let credential = try await credentialProvider. createAuthCredential ( )
743- try await user. reauthenticate ( with: credential)
744- } else {
745- throw AuthServiceError . providerNotFound ( " No provider found for \( providerId) " )
746+ let context = ReauthContext (
747+ providerId: providerId,
748+ providerName: getProviderDisplayName ( providerId) ,
749+ phoneNumber: currentUser? . phoneNumber,
750+ email: currentUser? . email
751+ )
752+
753+ switch providerId {
754+ case EmailAuthProviderID:
755+ throw AuthServiceError . emailReauthenticationRequired ( context: context)
756+ case PhoneAuthProviderID:
757+ throw AuthServiceError . phoneReauthenticationRequired ( context: context)
758+ default :
759+ throw AuthServiceError . simpleReauthenticationRequired ( context: context)
746760 }
747761 }
748762
@@ -769,13 +783,35 @@ public extension AuthService {
769783 ?? user. providerData. first? . providerID
770784
771785 guard let providerId = providerId else {
772- throw AuthServiceError . reauthenticationRequired (
786+ throw AuthServiceError . invalidCredentials (
773787 " Unable to determine sign-in provider for reauthentication "
774788 )
775789 }
776790
777791 return providerId
778792 }
793+
794+ /// Get a user-friendly display name for a provider ID
795+ /// - Parameter providerId: The provider ID from Firebase Auth
796+ /// - Returns: A user-friendly name for the provider
797+ private func getProviderDisplayName( _ providerId: String ) -> String {
798+ switch providerId {
799+ case EmailAuthProviderID:
800+ return " Email "
801+ case PhoneAuthProviderID:
802+ return " Phone "
803+ case " google.com " :
804+ return " Google "
805+ case " apple.com " :
806+ return " Apple "
807+ case " facebook.com " :
808+ return " Facebook "
809+ case " twitter.com " :
810+ return " Twitter "
811+ default :
812+ return providerId
813+ }
814+ }
779815
780816 func unenrollMFA( _ factorUid: String ) async throws -> [ MultiFactorInfo ] {
781817 guard let user = auth. currentUser else {
0 commit comments