1

I'm implementing phone number authentication in my Android app using Firebase. I'm able to initiate the verification process, and the onCodeSent() callback is triggered in my UserRepositoryImpl class, but the SMS message with the OTP never arrives on the device.

I've double-checked the following:

The phone number I'm using is one of the test numbers listed in the Firebase console under "Phone Numbers for Testing". I'm using the exact format (including the country code and "+" prefix) and case (uppercase/lowercase) as it appears in the console. My device can receive other SMS messages.

Here are the relevant code snippets:

PhoneSignUpViewModel.kt:

fun onSignUpClick(activity: Activity, phoneNumber: String) {
    viewModelScope.launch {
        isLoading = true

        // LOG: Check the number before sending to the repository
        Log.d("PhoneSignUpViewModel", "Phone number being sent to signUp: $phoneNumber")
        userRepository.signUp(phoneNumber) // No need to pass token here
            .collect { result ->
                when (result) {
                    is Result.Success -> {
                        // Update the shared state holder (verificationId and token are in result.data)
                        otpSharedStateHolder.otpVerificationData.value =
                            OtpVerificationData(
                                result.data.verificationId ?: "",
                                result.data.token
                            )
                        isLoading = false
                        _events.emit(Event.NavigateToOtpVerification)
                    }

                    is Result.Error -> {
                        showError = true
                        isLoading = false
                    }

                    is Result.Loading -> {
                        isLoading = true
                    }
                }
            }
    }
}

UserRepositoryImpl.kt:

   override fun signUp(
    phoneNumber: String,
    token: PhoneAuthProvider.ForceResendingToken?
): Flow<Result<User>> = callbackFlow {
    trySend(Result.Loading)

    launch {
        try {
            // LOG: Verify the number format received by the repository
            Log.d("UserRepositoryImpl", "Phone number received in signUp: $phoneNumber")
            val optionsBuilder = PhoneAuthOptions.newBuilder(firebaseAuth)
                .setPhoneNumber(phoneNumber)
                .setTimeout(60L, TimeUnit.SECONDS)
                .setCallbacks(object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
                    override fun onVerificationCompleted(credential: PhoneAuthCredential) {
                        // (Unlikely to happen for phone auth)
                        launch {
                            try {
                                firebaseAuth.signInWithCredential(credential).await()
                                val user = firebaseAuth.currentUser
                                trySend(
                                    Result.Success(
                                        User(
                                            phoneNumber = phoneNumber,
                                            id = user?.uid
                                        )
                                    )
                                )
                            } catch (e: Exception) {
                                trySend(
                                    Result.Error(
                                        Exception("Sign-in failed: ${e.message}")
                                    )
                                )
                            }
                        }
                    }

                    override fun onVerificationFailed(e: FirebaseException) {
                        Log.e(
                            "UserRepositoryImpl",
                            "onVerificationFailed: ${e.message}",
                            e
                        )
                        trySend(Result.Error(e))
                    }

                    override fun onCodeSent(
                        verificationId: String,
                        forceResendingToken: PhoneAuthProvider.ForceResendingToken
                    ) {
                        Log.d("UserRepositoryImpl", "onCodeSent: $verificationId")
                        trySend(
                            Result.Success(
                                User(
                                    phoneNumber = phoneNumber,
                                    verificationId = verificationId,
                                    token = forceResendingToken
                                )
                            )
                        )
                        close() // Close the callbackFlow
                    }
                })

            if (token != null) {
                optionsBuilder.setForceResendingToken(token)
            }

            val options = optionsBuilder.build()
            PhoneAuthProvider.verifyPhoneNumber(options)

        } catch (e: Exception) {
            trySend(Result.Error(e))
        }
    }

    awaitClose { /* Clean up resources if needed */ }
}.catch { emit(Result.Error(it as Exception)) }

Logcat Outputs :

  • D/PhoneSignUpViewModel: Phone number being sent to signUp: +16505550100
  • D/UserRepositoryImpl: Phone number received in signUp: +16505550100
  • D/UserRepositoryImpl: onCodeSent: [VERIFICATION_ID]

What I've Tried: I've carefully followed the Firebase documentation for phone number authentication (confused about playintegrity and appcheck). Added the manage debug token as well in firebase.

Tech Stack

  • Kotlin

  • Jetpack Compose

  • Hilt

  • Firebase Authentication

  • Play Integrity API(did it but not so clear about it)

3
  • Please do not share your personal details, like Phone number given above.
    – Arshad Ali
    Commented Aug 5, 2024 at 4:03
  • Thank you for your concern, but that's not a personal number its testing number provided by firebase Commented Aug 5, 2024 at 4:09
  • The number you used is a real phone number - It routes to the former directory assistance line for the 650 area code in the San Fran Bay Area (as do all 555-1212 numbers for their respective US area codes). The service likely only accepts land-line calls from the same area code, so it's probably not a big deal, but the NANPA which administers US phone numbers has designated certain numbers for fictitious use - I've replaced the real number with one of these in your question. Commented Oct 9, 2024 at 11:06

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.