diff --git a/auth/src/main/java/com/firebase/ui/auth/AuthException.kt b/auth/src/main/java/com/firebase/ui/auth/AuthException.kt
index 46d22f068..ae9d96e53 100644
--- a/auth/src/main/java/com/firebase/ui/auth/AuthException.kt
+++ b/auth/src/main/java/com/firebase/ui/auth/AuthException.kt
@@ -14,7 +14,10 @@
package com.firebase.ui.auth
+import android.content.Context
import com.firebase.ui.auth.AuthException.Companion.from
+import com.firebase.ui.auth.configuration.string_provider.AuthUIStringProvider
+import com.firebase.ui.auth.configuration.string_provider.DefaultAuthUIStringProvider
import com.google.firebase.FirebaseException
import com.google.firebase.auth.AuthCredential
import com.google.firebase.auth.FirebaseAuthException
@@ -341,15 +344,22 @@ abstract class AuthException(
* @return An appropriate [AuthException] subtype
*/
@JvmStatic
- fun from(firebaseException: Exception): AuthException {
+ fun from(firebaseException: Exception, context: Context): AuthException =
+ from(firebaseException, DefaultAuthUIStringProvider(context))
+
+ @JvmStatic
+ @JvmOverloads
+ fun from(firebaseException: Exception, stringProvider: AuthUIStringProvider? = null): AuthException {
return when (firebaseException) {
// If already an AuthException, return it directly
is AuthException -> firebaseException
-
+
// Handle specific Firebase Auth exceptions first (before general FirebaseException)
is FirebaseAuthInvalidCredentialsException -> {
InvalidCredentialsException(
- message = firebaseException.message ?: "Invalid credentials provided",
+ message = stringProvider?.errorInvalidCredentials.nonEmpty()
+ ?: firebaseException.message
+ ?: "Invalid credentials provided",
cause = firebaseException
)
}
@@ -357,17 +367,23 @@ abstract class AuthException(
is FirebaseAuthInvalidUserException -> {
when (firebaseException.errorCode) {
"ERROR_USER_NOT_FOUND" -> UserNotFoundException(
- message = firebaseException.message ?: "User not found",
+ message = stringProvider?.errorUserNotFound.nonEmpty()
+ ?: firebaseException.message
+ ?: "User not found",
cause = firebaseException
)
"ERROR_USER_DISABLED" -> InvalidCredentialsException(
- message = firebaseException.message ?: "User account has been disabled",
+ message = stringProvider?.errorUserDisabled.nonEmpty()
+ ?: firebaseException.message
+ ?: "User account has been disabled",
cause = firebaseException
)
else -> UserNotFoundException(
- message = firebaseException.message ?: "User account error",
+ message = stringProvider?.errorUserAccountGeneric.nonEmpty()
+ ?: firebaseException.message
+ ?: "User account error",
cause = firebaseException
)
}
@@ -375,7 +391,9 @@ abstract class AuthException(
is FirebaseAuthWeakPasswordException -> {
WeakPasswordException(
- message = firebaseException.message ?: "Password is too weak",
+ message = stringProvider?.errorWeakPasswordGeneric.nonEmpty()
+ ?: firebaseException.message
+ ?: "Password is too weak",
cause = firebaseException,
reason = firebaseException.reason
)
@@ -384,26 +402,31 @@ abstract class AuthException(
is FirebaseAuthUserCollisionException -> {
when (firebaseException.errorCode) {
"ERROR_EMAIL_ALREADY_IN_USE" -> EmailAlreadyInUseException(
- message = firebaseException.message
+ message = stringProvider?.errorEmailAlreadyInUse.nonEmpty()
+ ?: firebaseException.message
?: "Email address is already in use",
cause = firebaseException,
email = firebaseException.email
)
"ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL" -> AccountLinkingRequiredException(
- message = firebaseException.message
+ message = stringProvider?.errorAccountExistsDifferentCredential.nonEmpty()
+ ?: firebaseException.message
?: "Account already exists with different credentials",
cause = firebaseException
)
"ERROR_CREDENTIAL_ALREADY_IN_USE" -> AccountLinkingRequiredException(
- message = firebaseException.message
+ message = stringProvider?.errorCredentialAlreadyInUse.nonEmpty()
+ ?: firebaseException.message
?: "Credential is already associated with a different user account",
cause = firebaseException
)
else -> AccountLinkingRequiredException(
- message = firebaseException.message ?: "Account collision error",
+ message = stringProvider?.errorAccountCollisionGeneric.nonEmpty()
+ ?: firebaseException.message
+ ?: "Account collision error",
cause = firebaseException
)
}
@@ -411,7 +434,8 @@ abstract class AuthException(
is FirebaseAuthMultiFactorException -> {
MfaRequiredException(
- message = firebaseException.message
+ message = stringProvider?.errorMfaRequiredFallback.nonEmpty()
+ ?: firebaseException.message
?: "Multi-factor authentication required",
cause = firebaseException
)
@@ -419,23 +443,25 @@ abstract class AuthException(
is FirebaseAuthRecentLoginRequiredException -> {
InvalidCredentialsException(
- message = firebaseException.message
+ message = stringProvider?.errorRecentLoginRequired.nonEmpty()
+ ?: firebaseException.message
?: "Recent login required for this operation",
cause = firebaseException
)
}
is FirebaseAuthException -> {
- // Handle FirebaseAuthException and check for specific error codes
when (firebaseException.errorCode) {
"ERROR_TOO_MANY_REQUESTS" -> TooManyRequestsException(
- message = firebaseException.message
+ message = stringProvider?.errorTooManyRequests.nonEmpty()
+ ?: firebaseException.message
?: "Too many requests. Please try again later",
cause = firebaseException
)
else -> UnknownException(
- message = firebaseException.message
+ message = stringProvider?.errorUnknownAuth.nonEmpty()
+ ?: firebaseException.message
?: "An unknown authentication error occurred",
cause = firebaseException
)
@@ -443,33 +469,36 @@ abstract class AuthException(
}
is FirebaseException -> {
- // Handle general Firebase exceptions, which include network errors
NetworkException(
- message = firebaseException.message ?: "Network error occurred",
+ message = stringProvider?.errorNetworkGeneric.nonEmpty()
+ ?: firebaseException.message
+ ?: "Network error occurred",
cause = firebaseException
)
}
else -> {
- // Check for common cancellation patterns
- if (firebaseException.message?.contains(
- "cancelled",
- ignoreCase = true
- ) == true ||
+ if (firebaseException.message?.contains("cancelled", ignoreCase = true) == true ||
firebaseException.message?.contains("canceled", ignoreCase = true) == true
) {
AuthCancelledException(
- message = firebaseException.message ?: "Authentication was cancelled",
+ message = stringProvider?.errorAuthCancelled.nonEmpty()
+ ?: firebaseException.message
+ ?: "Authentication was cancelled",
cause = firebaseException
)
} else {
UnknownException(
- message = firebaseException.message ?: "An unknown error occurred",
+ message = stringProvider?.errorUnknownAuth.nonEmpty()
+ ?: firebaseException.message
+ ?: "An unknown error occurred",
cause = firebaseException
)
}
}
}
}
+
+ private fun String?.nonEmpty(): String? = this?.ifEmpty { null }
}
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/FirebaseAuthUI.kt b/auth/src/main/java/com/firebase/ui/auth/FirebaseAuthUI.kt
index 9f829a37f..a4d31f1a7 100644
--- a/auth/src/main/java/com/firebase/ui/auth/FirebaseAuthUI.kt
+++ b/auth/src/main/java/com/firebase/ui/auth/FirebaseAuthUI.kt
@@ -391,7 +391,7 @@ class FirebaseAuthUI private constructor(
throw e
} catch (e: Exception) {
// Map to appropriate AuthException
- val authException = AuthException.from(e)
+ val authException = AuthException.from(e, context)
updateAuthState(AuthState.Error(authException))
throw authException
}
@@ -457,7 +457,7 @@ class FirebaseAuthUI private constructor(
throw e
} catch (e: Exception) {
// Map to appropriate AuthException
- val authException = AuthException.from(e)
+ val authException = AuthException.from(e, context)
updateAuthState(AuthState.Error(authException))
throw authException
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/AnonymousAuthProvider+FirebaseAuthUI.kt b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/AnonymousAuthProvider+FirebaseAuthUI.kt
index 009765727..746537390 100644
--- a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/AnonymousAuthProvider+FirebaseAuthUI.kt
+++ b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/AnonymousAuthProvider+FirebaseAuthUI.kt
@@ -20,6 +20,7 @@ import kotlinx.coroutines.tasks.await
*/
@Composable
internal fun FirebaseAuthUI.rememberAnonymousSignInHandler(): () -> Unit {
+ val context = androidx.compose.ui.platform.LocalContext.current
val coroutineScope = rememberCoroutineScope()
return remember(this) {
{
@@ -30,7 +31,7 @@ internal fun FirebaseAuthUI.rememberAnonymousSignInHandler(): () -> Unit {
// Already an AuthException, don't re-wrap it
updateAuthState(AuthState.Error(e))
} catch (e: Exception) {
- val authException = AuthException.from(e)
+ val authException = AuthException.from(e, context)
updateAuthState(AuthState.Error(authException))
}
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/EmailAuthProvider+FirebaseAuthUI.kt b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/EmailAuthProvider+FirebaseAuthUI.kt
index 8d4bae6d1..61b50c613 100644
--- a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/EmailAuthProvider+FirebaseAuthUI.kt
+++ b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/EmailAuthProvider+FirebaseAuthUI.kt
@@ -225,7 +225,7 @@ internal suspend fun FirebaseAuthUI.createOrLinkUserWithEmailAndPassword(
updateAuthState(AuthState.Error(e))
throw e
} catch (e: Exception) {
- val authException = AuthException.from(e)
+ val authException = AuthException.from(e, context)
updateAuthState(AuthState.Error(authException))
throw authException
}
@@ -450,7 +450,7 @@ internal suspend fun FirebaseAuthUI.signInWithEmailAndPassword(
updateAuthState(AuthState.Error(e))
throw e
} catch (e: Exception) {
- val authException = AuthException.from(e)
+ val authException = AuthException.from(e, context)
updateAuthState(AuthState.Error(authException))
throw authException
}
@@ -766,7 +766,7 @@ internal suspend fun FirebaseAuthUI.sendSignInLinkToEmail(
updateAuthState(AuthState.Error(e))
throw e
} catch (e: Exception) {
- val authException = AuthException.from(e)
+ val authException = AuthException.from(e, context)
updateAuthState(AuthState.Error(authException))
throw authException
}
@@ -987,7 +987,7 @@ internal suspend fun FirebaseAuthUI.signInWithEmailLink(
updateAuthState(AuthState.Error(e))
throw e
} catch (e: Exception) {
- val authException = AuthException.from(e)
+ val authException = AuthException.from(e, context)
updateAuthState(AuthState.Error(authException))
throw authException
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/FacebookAuthProvider+FirebaseAuthUI.kt b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/FacebookAuthProvider+FirebaseAuthUI.kt
index 28ef45636..c87748ea9 100644
--- a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/FacebookAuthProvider+FirebaseAuthUI.kt
+++ b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/FacebookAuthProvider+FirebaseAuthUI.kt
@@ -86,7 +86,7 @@ internal fun FirebaseAuthUI.rememberSignInWithFacebookLauncher(
// Already an AuthException, don't re-wrap it
updateAuthState(AuthState.Error(e))
} catch (e: Exception) {
- val authException = AuthException.from(e)
+ val authException = AuthException.from(e, context)
updateAuthState(AuthState.Error(authException))
}
}
@@ -98,7 +98,7 @@ internal fun FirebaseAuthUI.rememberSignInWithFacebookLauncher(
override fun onError(error: FacebookException) {
Log.e("FacebookAuthProvider", "Error during Facebook sign in", error)
- val authException = AuthException.from(error)
+ val authException = AuthException.from(error, context)
updateAuthState(
AuthState.Error(
authException
@@ -190,7 +190,7 @@ internal suspend fun FirebaseAuthUI.signInWithFacebook(
updateAuthState(AuthState.Error(e))
throw e
} catch (e: FacebookException) {
- val authException = AuthException.from(e)
+ val authException = AuthException.from(e, context)
updateAuthState(AuthState.Error(authException))
throw authException
} catch (e: CancellationException) {
@@ -204,7 +204,7 @@ internal suspend fun FirebaseAuthUI.signInWithFacebook(
updateAuthState(AuthState.Error(e))
throw e
} catch (e: Exception) {
- val authException = AuthException.from(e)
+ val authException = AuthException.from(e, context)
updateAuthState(AuthState.Error(authException))
throw authException
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProvider+FirebaseAuthUI.kt b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProvider+FirebaseAuthUI.kt
index 4d18cb0a9..f8cbbdddf 100644
--- a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProvider+FirebaseAuthUI.kt
+++ b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/GoogleAuthProvider+FirebaseAuthUI.kt
@@ -67,7 +67,7 @@ internal fun FirebaseAuthUI.rememberGoogleSignInHandler(
} catch (e: AuthException) {
updateAuthState(AuthState.Error(e))
} catch (e: Exception) {
- val authException = AuthException.from(e)
+ val authException = AuthException.from(e, context)
updateAuthState(AuthState.Error(authException))
}
}
@@ -128,7 +128,7 @@ internal suspend fun FirebaseAuthUI.signInWithGoogle(
authorizationProvider.authorize(context, requestedScopes)
} catch (e: Exception) {
// Continue with sign-in even if scope authorization fails
- val authException = AuthException.from(e)
+ val authException = AuthException.from(e, context)
updateAuthState(AuthState.Error(authException))
}
}
@@ -227,7 +227,7 @@ internal suspend fun FirebaseAuthUI.signInWithGoogle(
throw e
} catch (e: Exception) {
- val authException = AuthException.from(e)
+ val authException = AuthException.from(e, context)
updateAuthState(AuthState.Error(authException))
throw authException
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/OAuthProvider+FirebaseAuthUI.kt b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/OAuthProvider+FirebaseAuthUI.kt
index 485065746..4053684d6 100644
--- a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/OAuthProvider+FirebaseAuthUI.kt
+++ b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/OAuthProvider+FirebaseAuthUI.kt
@@ -74,7 +74,7 @@ internal fun FirebaseAuthUI.rememberOAuthSignInHandler(
} catch (e: AuthException) {
updateAuthState(AuthState.Error(e))
} catch (e: Exception) {
- val authException = AuthException.from(e)
+ val authException = AuthException.from(e, context)
updateAuthState(AuthState.Error(authException))
}
}
@@ -231,7 +231,7 @@ internal suspend fun FirebaseAuthUI.signInWithProvider(
throw e
} catch (e: Exception) {
- val authException = AuthException.from(e)
+ val authException = AuthException.from(e, context)
updateAuthState(AuthState.Error(authException))
throw authException
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/PhoneAuthProvider+FirebaseAuthUI.kt b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/PhoneAuthProvider+FirebaseAuthUI.kt
index 0be8ee8fa..dd8662064 100644
--- a/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/PhoneAuthProvider+FirebaseAuthUI.kt
+++ b/auth/src/main/java/com/firebase/ui/auth/configuration/auth_provider/PhoneAuthProvider+FirebaseAuthUI.kt
@@ -224,7 +224,7 @@ internal suspend fun FirebaseAuthUI.submitVerificationCode(
updateAuthState(AuthState.Error(e))
throw e
} catch (e: Exception) {
- val authException = AuthException.from(e)
+ val authException = AuthException.from(e, context)
updateAuthState(AuthState.Error(authException))
throw authException
}
@@ -334,7 +334,7 @@ internal suspend fun FirebaseAuthUI.signInWithPhoneAuthCredential(
updateAuthState(AuthState.Error(e))
throw e
} catch (e: Exception) {
- val authException = AuthException.from(e)
+ val authException = AuthException.from(e, context)
updateAuthState(AuthState.Error(authException))
throw authException
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/AuthUIStringProvider.kt b/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/AuthUIStringProvider.kt
index a062debdd..bc7a8acdb 100644
--- a/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/AuthUIStringProvider.kt
+++ b/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/AuthUIStringProvider.kt
@@ -542,4 +542,53 @@ interface AuthUIStringProvider {
/** Tooltip message shown when MFA is disabled */
val mfaDisabledTooltip: String
+
+ // =============================================================================================
+ // AuthException error messages
+ // =============================================================================================
+
+ /** Error when a user account has been disabled by an administrator. */
+ val errorUserDisabled: String
+
+ /** Error when provided credentials are invalid. Return empty to use the Firebase SDK message. */
+ val errorInvalidCredentials: String
+
+ /** Error when the user account does not exist. Return empty to use the Firebase SDK message. */
+ val errorUserNotFound: String
+
+ /** Generic error for unexpected user account issues. Return empty to use the Firebase SDK message. */
+ val errorUserAccountGeneric: String
+
+ /** Error when the password is too weak. Return empty to use the Firebase SDK message. */
+ val errorWeakPasswordGeneric: String
+
+ /** Error when the email address is already registered. Return empty to use the Firebase SDK message. */
+ val errorEmailAlreadyInUse: String
+
+ /** Error when an account already exists with a different sign-in method. Return empty to use the Firebase SDK message. */
+ val errorAccountExistsDifferentCredential: String
+
+ /** Error when a credential is already linked to another account. Return empty to use the Firebase SDK message. */
+ val errorCredentialAlreadyInUse: String
+
+ /** Generic error for account collision issues. Return empty to use the Firebase SDK message. */
+ val errorAccountCollisionGeneric: String
+
+ /** Error when multi-factor authentication is required. Return empty to use the Firebase SDK message. */
+ val errorMfaRequiredFallback: String
+
+ /** Error when the operation requires a recent sign-in. Return empty to use the Firebase SDK message. */
+ val errorRecentLoginRequired: String
+
+ /** Error when sign-in is blocked due to too many attempts. Return empty to use the Firebase SDK message. */
+ val errorTooManyRequests: String
+
+ /** Generic unknown authentication error. Return empty to use the Firebase SDK message. */
+ val errorUnknownAuth: String
+
+ /** Error for network failures during authentication. Return empty to use the Firebase SDK message. */
+ val errorNetworkGeneric: String
+
+ /** Error when authentication is cancelled. Return empty to use the Firebase SDK message. */
+ val errorAuthCancelled: String
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/DefaultAuthUIStringProvider.kt b/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/DefaultAuthUIStringProvider.kt
index 429d6d286..3d2b9772d 100644
--- a/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/DefaultAuthUIStringProvider.kt
+++ b/auth/src/main/java/com/firebase/ui/auth/configuration/string_provider/DefaultAuthUIStringProvider.kt
@@ -494,4 +494,49 @@ class DefaultAuthUIStringProvider(
override val mfaDisabledTooltip: String
get() = localizedContext.getString(R.string.fui_mfa_disabled_tooltip)
+
+ override val errorUserDisabled: String
+ get() = localizedContext.getString(R.string.fui_error_user_disabled)
+
+ override val errorInvalidCredentials: String
+ get() = localizedContext.getString(R.string.fui_error_invalid_credentials)
+
+ override val errorUserNotFound: String
+ get() = localizedContext.getString(R.string.fui_error_user_not_found)
+
+ override val errorUserAccountGeneric: String
+ get() = localizedContext.getString(R.string.fui_error_user_account_generic)
+
+ override val errorWeakPasswordGeneric: String
+ get() = localizedContext.getString(R.string.fui_error_weak_password_generic)
+
+ override val errorEmailAlreadyInUse: String
+ get() = localizedContext.getString(R.string.fui_error_email_already_in_use)
+
+ override val errorAccountExistsDifferentCredential: String
+ get() = localizedContext.getString(R.string.fui_error_account_exists_different_credential)
+
+ override val errorCredentialAlreadyInUse: String
+ get() = localizedContext.getString(R.string.fui_error_credential_already_in_use)
+
+ override val errorAccountCollisionGeneric: String
+ get() = localizedContext.getString(R.string.fui_error_account_collision_generic)
+
+ override val errorMfaRequiredFallback: String
+ get() = localizedContext.getString(R.string.fui_error_mfa_required_fallback)
+
+ override val errorRecentLoginRequired: String
+ get() = localizedContext.getString(R.string.fui_error_recent_login_required)
+
+ override val errorTooManyRequests: String
+ get() = localizedContext.getString(R.string.fui_error_too_many_requests)
+
+ override val errorUnknownAuth: String
+ get() = localizedContext.getString(R.string.fui_error_unknown_auth)
+
+ override val errorNetworkGeneric: String
+ get() = localizedContext.getString(R.string.fui_error_network_generic)
+
+ override val errorAuthCancelled: String
+ get() = localizedContext.getString(R.string.fui_error_auth_cancelled)
}
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/screens/FirebaseAuthScreen.kt b/auth/src/main/java/com/firebase/ui/auth/ui/screens/FirebaseAuthScreen.kt
index 5a065400c..98ecf5542 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/screens/FirebaseAuthScreen.kt
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/screens/FirebaseAuthScreen.kt
@@ -361,7 +361,7 @@ fun FirebaseAuthScreen(
authUI.signOut(context)
// Keep sign-in preference for "Continue as..." on next launch
} catch (e: Exception) {
- onSignInFailure(AuthException.from(e))
+ onSignInFailure(AuthException.from(e, stringProvider))
} finally {
pendingLinkingCredential.value = null
pendingResolver.value = null
@@ -442,7 +442,7 @@ fun FirebaseAuthScreen(
onComplete = { navController.popBackStack() },
onSkip = { navController.popBackStack() },
onError = { exception ->
- onSignInFailure(AuthException.from(exception))
+ onSignInFailure(AuthException.from(exception, stringProvider))
}
)
} else {
@@ -467,7 +467,7 @@ fun FirebaseAuthScreen(
navController.popBackStack()
},
onError = { exception ->
- onSignInFailure(AuthException.from(exception))
+ onSignInFailure(AuthException.from(exception, stringProvider))
}
)
} else {
@@ -598,7 +598,7 @@ fun FirebaseAuthScreen(
LaunchedEffect(errorState) {
val exception = when (val throwable = errorState.exception) {
is AuthException -> throwable
- else -> AuthException.from(throwable)
+ else -> AuthException.from(throwable, stringProvider)
}
dialogController.showErrorDialog(
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/EmailAuthScreen.kt b/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/EmailAuthScreen.kt
index 2ebc2542f..62972d18c 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/EmailAuthScreen.kt
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/EmailAuthScreen.kt
@@ -181,7 +181,7 @@ fun EmailAuthScreen(
}
is AuthState.Error -> {
- val exception = AuthException.from(state.exception)
+ val exception = AuthException.from(state.exception, stringProvider)
onError(exception)
dialogController?.showErrorDialog(
exception = exception,
@@ -265,7 +265,7 @@ fun EmailAuthScreen(
skipCredentialSave = isUsingRetrievedCredential
)
} catch (e: Exception) {
- onError(AuthException.from(e))
+ onError(AuthException.from(e, stringProvider))
}
}
},
@@ -290,7 +290,7 @@ fun EmailAuthScreen(
)
}
} catch (e: Exception) {
- onError(AuthException.from(e))
+ onError(AuthException.from(e, stringProvider))
}
}
},
diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/PhoneAuthScreen.kt b/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/PhoneAuthScreen.kt
index fa6278976..26161da78 100644
--- a/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/PhoneAuthScreen.kt
+++ b/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/PhoneAuthScreen.kt
@@ -210,7 +210,7 @@ fun PhoneAuthScreen(
}
is AuthState.Error -> {
- val exception = AuthException.from(state.exception)
+ val exception = AuthException.from(state.exception, stringProvider)
onError(exception)
// Show dialog for phone-specific errors using top-level controller
diff --git a/auth/src/main/res/values/strings.xml b/auth/src/main/res/values/strings.xml
index bb4b4e813..cc5cfa6b3 100644
--- a/auth/src/main/res/values/strings.xml
+++ b/auth/src/main/res/values/strings.xml
@@ -222,6 +222,23 @@
Additional verification required. Please complete multi-factor authentication.
Account needs to be linked. Please try a different sign-in method.
Authentication was cancelled. Please try again when ready.
+
+ User account has been disabled
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Choose Authentication Method
diff --git a/auth/src/test/java/com/firebase/ui/auth/AuthExceptionTest.kt b/auth/src/test/java/com/firebase/ui/auth/AuthExceptionTest.kt
index 0b7b5bbbf..caa382bb1 100644
--- a/auth/src/test/java/com/firebase/ui/auth/AuthExceptionTest.kt
+++ b/auth/src/test/java/com/firebase/ui/auth/AuthExceptionTest.kt
@@ -14,11 +14,15 @@
package com.firebase.ui.auth
+import com.firebase.ui.auth.configuration.string_provider.AuthUIStringProvider
import com.google.common.truth.Truth.assertThat
import com.google.firebase.FirebaseException
import com.google.firebase.auth.FirebaseAuthException
+import com.google.firebase.auth.FirebaseAuthInvalidUserException
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+import org.mockito.kotlin.whenever
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
@@ -136,4 +140,47 @@ class AuthExceptionTest {
// Assert
assertThat(exception.email).isEqualTo(email)
}
+
+ // =============================================================================================
+ // AuthUIStringProvider message customisation
+ // =============================================================================================
+
+ @Test
+ fun `from() uses string provider message when non-empty`() {
+ val firebaseException = mock(FirebaseAuthInvalidUserException::class.java)
+ whenever(firebaseException.errorCode).thenReturn("ERROR_USER_DISABLED")
+ whenever(firebaseException.message).thenReturn("Firebase: user disabled")
+
+ val stringProvider = mock(AuthUIStringProvider::class.java)
+ whenever(stringProvider.errorUserDisabled).thenReturn("Custom: account disabled")
+
+ val result = AuthException.from(firebaseException, stringProvider)
+
+ assertThat(result.message).isEqualTo("Custom: account disabled")
+ }
+
+ @Test
+ fun `from() falls back to Firebase message when string provider returns empty`() {
+ val firebaseException = mock(FirebaseAuthInvalidUserException::class.java)
+ whenever(firebaseException.errorCode).thenReturn("ERROR_USER_DISABLED")
+ whenever(firebaseException.message).thenReturn("Firebase: user disabled")
+
+ val stringProvider = mock(AuthUIStringProvider::class.java)
+ whenever(stringProvider.errorUserDisabled).thenReturn("")
+
+ val result = AuthException.from(firebaseException, stringProvider)
+
+ assertThat(result.message).isEqualTo("Firebase: user disabled")
+ }
+
+ @Test
+ fun `from() falls back to Firebase message when no string provider given`() {
+ val firebaseException = mock(FirebaseAuthInvalidUserException::class.java)
+ whenever(firebaseException.errorCode).thenReturn("ERROR_USER_DISABLED")
+ whenever(firebaseException.message).thenReturn("Firebase: user disabled")
+
+ val result = AuthException.from(firebaseException)
+
+ assertThat(result.message).isEqualTo("Firebase: user disabled")
+ }
}
\ No newline at end of file