2

I am currently facing an issue where in my Play-Store version of the Flutter app, whenever a user goes through the login process, they enter their phone number and after the verified their phone number via _firebaseAuth.verifyPhoneNumber they are taken to OTP screen where they have to enter OTP that is received on their device but when even after entering the correct OTP, the user will face "sms code has expired please resend the sms code and try again" Snackbar message.

This really seems unusual as I didn't face any issue like this during the internal testing or in debug mode and have signed my app with the upload-key from the Play console, I also further checked that my debug mode/test app shows SHA-256 of Upload key certificate and my play store app shows SHA-256 of App signing key certificate via Asset Link Tools + I even added every SHA-7/256 keys to the Firebase Project Settings as well. I also noticed that google.cloud.identitytoolkit.v1.AuthenticationService.SignInWithPhoneNumber showed 53% of errors in my Identity Toolkit API in google cloud leading me to believe that the issue is definitely related to the code which I am not quite able to figure out what is really causing this aka root of the problem...

This is my flutter code that is handling the login part:

utils.dart

class AuthProvider extends ChangeNotifier {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;

void signInWithPhone(BuildContext context, String phoneNumber, Function() onVerificationSuccess) async {
    try {
      await _firebaseAuth.verifyPhoneNumber(
          phoneNumber: phoneNumber,
          verificationCompleted:
              (PhoneAuthCredential phoneAuthCredential) async {
            await _firebaseAuth.signInWithCredential(phoneAuthCredential);
          },
          verificationFailed: (error) {
            toastBar(context, error.message.toString());
          },
          codeSent: (verificationId, forceResendingToken) {
            Navigator.of(context).push(createRoute(LoginScreen2(
              phone: phoneNumber,
              verficationId: verificationId,
            )));

            onVerificationSuccess();
          },
          timeout: const Duration(seconds: 60),
          codeAutoRetrievalTimeout: (verificationId) {
            showSnackBar(context, 'OTP retrieval timed out. Please try again.');
          });
    } on FirebaseAuthException catch (e) {
      toastBar(context, e.message.toString());
    }
  }

void verifyOtp({
    required BuildContext context,
    required String verificationId,
    required String userOtp,
    required Function onSuccess,
  }) async {
    notifyListeners();

    try {
      PhoneAuthCredential creds = PhoneAuthProvider.credential(
          verificationId: verificationId, smsCode: userOtp);

      User? user = (await _firebaseAuth.signInWithCredential(creds)).user;

      if (user != null) {
        // carry our logic
        onSuccess();
      }

      notifyListeners();
    } on FirebaseAuthException catch (e) {
      showSnackBar(context, e.message.toString());
      notifyListeners();
    }
  }

Future userSignOut() async {
    await _firebaseAuth.signOut();
    notifyListeners();
  }
}

Based on the above explanation, it seems signInWithPhone() works perfectly, so the error is probably in the verifyOtp() part but what exactly?

otp.dart

// verify otp
  void verifyOtp(BuildContext context, String userOtp) {
    final ap = Provider.of<AuthProvider>(context, listen: false);
    ap.verifyOtp(
      context: context,
      verificationId: widget.verficationId,
      userOtp: userOtp,
      onSuccess: () {
        // checking whether user exists in the db
        uid = FirebaseAuth.instance.currentUser?.uid;
        FirebaseFirestore.instance
            .collection('Users')
            .doc(uid)
            .get()
            .then((value) async {
              // handles the sucess
        });
      },
    );
  }

login.dart

void sendPhoneNumber() {
    setState(() {
      _loading = true;
    });

    final ap = Provider.of<AuthProvider>(context, listen: false);
    ap.signInWithPhone(
      context,
      "+91${_controller.text}",
      () {
        // Callback function: invoked after verification and navigation
        setState(() {
          _loading = false;
        });

        // Perform any additional actions here
      },
    );
  }

Added this in case it's any important:

await FirebaseAppCheck.instance.activate(
    webRecaptchaSiteKey: _webKey,
    androidProvider: kDebugMode ? AndroidProvider.debug : AndroidProvider.playIntegrity,
    appleProvider: AppleProvider.appAttest,
  );

Maybe I should remove the _firebaseAuth.signInWithCredential(creds) that’s being used twice but wouldn’t that remove auto sign-in like similar to earlier version of Play Integrity.

A very very thank-you to whoever helps me in finding the bug in this issue!

  • Did you add SHA-1 certificate from Google Store to Firebase project. – Ankit Tale Aug 05 '23 at 15:56
  • Path Release Management > App Signing > Search SHA Certificate > Download > the go to Firebase Console > Your App > Add that certificate > Project Settings – Ankit Tale Aug 05 '23 at 15:58
  • Does this answer your question? [Firebase Phone Auth not working in release build](https://stackoverflow.com/questions/53034419/firebase-phone-auth-not-working-in-release-build) – Ankit Tale Aug 05 '23 at 15:59
  • 1
    @AnkitTale Actually I have already done that, but here is an update I tried removing ```await _firebaseAuth.signInWithCredential(phoneAuthCredential);``` from signInFromPhone function, and everything is working fine, like in the release version people can now easily sign by entering the OTP in once it drops, but only question remains now is how can I trigger the auto-sign that we used to have during SafetyNet like once OTP pops up and the app will automatically let us sign in ??? – ItsHarsh.json Aug 06 '23 at 10:16

0 Answers0