firebase / firebase-android-sdk

Firebase Android SDK
https://firebase.google.com
Apache License 2.0
2.24k stars 568 forks source link

Firebase OTP - The SMS code has expired. #5872

Closed Surkhojb closed 3 months ago

Surkhojb commented 3 months ago

[REQUIRED] Step 2: Describe your environment

[REQUIRED] Step 3: Describe the problem

Steps to reproduce:

We are facing an issue trying to do log in with Phone. Once we requested for the OTP we receive the OTP but the moment we validate the OTP we are getting the current message: The SMS code has expired. Please re-send the verification code to try again.

Relevant Code:

Dependencies:

    const val bom = "com.google.firebase:firebase-bom:32.7.4"
    const val auth = "com.google.firebase:firebase-auth"
    const val config = "com.google.firebase:firebase-config"
    const val analytics = "com.google.firebase:firebase-analytics"
    const val database = "com.google.firebase:firebase-database"
    const val messaging = "com.google.firebase:firebase-messaging"
    const val functions = "com.google.firebase:firebase-functions"
    const val firestore = "com.google.firebase:firebase-firestore"
    const val dynamicLinks = "com.google.firebase:firebase-dynamic-links"
    const val inAppMessaging = "com.google.firebase:firebase-inappmessaging-display"
    const val crashlytics = "com.google.firebase:firebase-crashlytics"
    const val performance = "com.google.firebase:firebase-perf"

Auth Implementation

private fun verifyPhoneNumber(phoneNumber: String) {
        val auth = FirebaseAuth.getInstance()
        auth.setLanguageCode(viewModel.getAppLanguageCode())
        val options = PhoneAuthOptions.newBuilder(auth)
            .setPhoneNumber(phoneNumber)
            .setTimeout(60, TimeUnit.SECONDS)
            .setActivity(requireActivity())
            .setCallbacks(viewModel.callbacks)
        viewModel.resendToken?.let { options.setForceResendingToken(it) }
        PhoneAuthProvider.verifyPhoneNumber(options.build())
    }

var callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
        override fun onVerificationCompleted(credential: PhoneAuthCredential) {
            isLoading.set(false)
            signInWithPhoneAuthCredential(credential)
        }

        override fun onVerificationFailed(e: FirebaseException) {
            isLoading.set(false)
            if (e is FirebaseAuthInvalidCredentialsException) {
                sendError(Error(ErrorType.ERROR_INVALID_PHONE_NUMBER))
            } else if (e is FirebaseTooManyRequestsException) {
                sendError(Error(ErrorType.ERROR_OTHER, e.getLocalizedMessage()))
            }

            if (BuildConfig.DEBUG) e.printStackTrace()
        }

        override fun onCodeSent(id: String, token: PhoneAuthProvider.ForceResendingToken) {
            resendToken = token
            verificationId = id
            onCodeSent()
        }
    }

fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential) {
        isLoading.set(true)
        if (isVerifyingUser) {
            userManager.reauthenticate(credential, object : CompletionCallback<Void> {
                override fun onSuccess(result: Void?) {
                    isLoading.set(false)
                    sendEvent(ActionType.FINISH_ACTIVITY)
                }

                override fun onFailure(error: Error?) {
                    sendError(Error(ErrorType.ERROR_LOGIN_METHOD_DOES_NOT_MATCH))
                }
            })
        } else {
            userManager.loginPhone(credential, object : CompletionCallback<Void> {
                override fun onSuccess(result: Void?) {
                    clearVerificationCode()
                    isLoading.set(false)
                    userManager.saveName(name)
                }

                override fun onFailure(error: Error?) {
                    clearVerificationCode()
                    isLoading.set(false)
                    sendError(error)
                    userManager.didUserJustLogIn = false
                }
            })
        }
        userManager.loginPhone(credential, object : CompletionCallback<Void> {
            override fun onSuccess(result: Void?) {
                clearVerificationCode()
                isLoading.set(false)
                userManager.saveName(name)
            }

            override fun onFailure(error: Error?) {
                clearVerificationCode()
                isLoading.set(false)
                sendError(error)
                userManager.didUserJustLogIn = false
            }
        })
    }

NOTE -> Currently I am only able to reproduce once the app is signed with release keys to be uploaded to store. I am not able to use debug build due to Re-CAPTCHA mechanism

google-oss-bot commented 3 months ago

I found a few problems with this issue: