Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The sms code has expired. Please re-send the verification code to try again

Whenever I tried to login with phone number using react-native-firebase sdk, I recieve OTP code through sms and when I submit the recieved code, an error is there saying:"The sms code has expired. Please re-send the verification code to try again." And here point to be noted that an entry for respective phone number is writing in Users section of firebase even there is an error.

I am using following:

NodeJS: v8.11.1,
NPM: v5.6.0,
react-native: "^0.59.9",
react-native-firebase: "^5.5.3"

Some links I have already tried are:

1. https://github.com/invertase/react-native-firebase- 
docs/blob/master/docs/auth/phone-auth.md
2. https://stackoverflow.com/questions/46522726/firebase-phone- 
authentication-error-the-sms-code-has-expired
3. https://www.bountysource.com/issues/45308170-firebase-phone- 
number-auth-integration
4. https://medium.com/@chrisbianca/getting-started-with-firebase- 
authentication-on-react-native-a1ed3d2d6d91
5. https://invertase.io/oss/react-native-firebase/v6/auth/phone- 
auth

In MobileRegistration.js:

navigateToOtpScreen() {
console.log("Phone number: ", "+91" + this.state.phoneNumber)
firebase.auth().signInWithPhoneNumber("+91" + 
this.state.phoneNumber)
.then(confirmResult => {
   this.setState({ confirmResult, message: 'Code has been sent!'})
   this.props.navigation.navigate('EnterOtp', { 'confirmResult': 
   confirmResult})
 })
 .catch(error => {
      alert(error.message);
      this.setState({ message: `Sign In With Phone Number Error: 
      ${error.message}` })
  });

};

In EnterOtp.js:

componentDidMount() {
this.unsubscribe = firebase.auth().onAuthStateChanged((user) => {
    alert(JSON.stringify(user));
    if (user) {
        this.setState({
            user: user.toJSON()
        });
    } else {
        // User has been signed out, reset the state
        this.setState({
            user: null,
            message: '',
            otp: '',
            otp1: '',
            otp2: '',
            otp3: '',
            otp4: '',
            otp5: '',
            otp6: ''

        });
    }
});

}

componentWillUnmount() {
if (this.unsubscribe) this.unsubscribe();

}

verifyOTP = async () => {
const {
    confirmResult,
} = this.props.navigation.state.params;
let otp = this.state.otp + "" + this.state.otp1 + "" + this.state.otp2 + "" + this.state.otp3 + "" + this.state.otp4 + "" + this.state.otp5 + "" + this.state.otp6
if (confirmResult && otp.length) {

    alert(otp);
    confirmResult.confirm(otp).then((user) => {
            AsyncStorage.setItem('accessToken', confirmResult._verificationId);
            this.props.navigation.navigate('SetupCoverVideo');
            this.setState({
                message: 'Code Confirmed!'
            });
        })
        .catch(error => {
            alert(error.message) && this.setState({
                message: `Code Confirm Error: ${error.message}`
            })
        });
}

}

Expected Result: Code should be verified and an entry should be in Users section of firebase and navigate to SetupCoverVideo.

Actual Result: Facing an error saying: "The sms code has expired. Please re-send the verification code to try again." And here point to be noted that an entry for respective phone number is writing in Users section of firebase even there is an error.

I am wondering for the solution. Anyone please assist me.

like image 612
Ranu Kumar Avatar asked Jul 16 '19 10:07

Ranu Kumar


2 Answers

You need to check for background authentication using:

conponentDidMount() {    
firebase.auth().onAuthStateChanged((user) => {
            if (user) {
                // alert(JSON.stringify(user))
                // Obviously, you can add more statements here, 
                //       e.g. call an action creator if you use Redux. 
                // navigate the user away from the login screens: 
            }
        });
}

Then you need to log out your user once you are done with it (I faced this issue of old user session already present while new user was coming to authenticate)

So, at the time of logging out use:

if (firebase.auth().currentUser)
            firebase.auth().currentUser.delete();

And you are all set!

like image 106
salvi shahzad Avatar answered Sep 19 '22 10:09

salvi shahzad


Apparently, some recent versions of Android are smart enough to receive the SMS verification code and use it to authenticate the user. This authentication happens in the background while the user still receives the verification code in an SMS. When the user tries to enter the verification code, he/she gets a message that the verification code expired, because Android has already used it (in the background) and has already logged in the user! To double-check that, check the Firebase Console. You should find that this new user has been added to the list of users.

To avoid receiving the verification code expiry message, we need to set up a listener for "authentication changes." As soon as Android logs in the user in the background, this listener should navigate the user away from the login screen, in which he/she was supposed to enter the verification code. The following demonstrates how this can be implemented. I would add the following code to the login screen.

Example code for use with functional components:

useEffect( () => {
    firebase.auth().onAuthStateChanged( (user) => {
        if (user) {
            // Obviously, you can add more statements here, 
            //       e.g. call an action creator if you use Redux. 

            // navigate the user away from the login screens: 
            props.navigation.navigate("PermissionsScreen");
        } 
        else 
        {
            // reset state if you need to  
            dispatch({ type: "reset_user" });
        }
    });
}, []);  

Example code for use with class components:

// I did NOT test this version, because I use functional components. 
componentDidMount() {
    firebase.auth().onAuthStateChanged( (user) => {
        if (user) {
            // Obviously, you can add more statements here, 
            //       e.g. call an action creator if you use Redux. 

            // navigate the user away from the login screens: 
            props.navigation.navigate("PermissionsScreen");
        } 
        else 
        {
            // reset state if you need to 
            this.setState({
                user: null,
                messageText: '',
                codeInput: '',
                phoneNo: '',
                confirmResult: null,
            });
        }
    });
};  
like image 35
Bilal Abdeen Avatar answered Sep 20 '22 10:09

Bilal Abdeen