2

I am working with React-Redux-Firebase. I implemented signing in with phone number. Now I am trying to implement error handling. When number is invalid I display window alert with error message. The only thing left to do is to reset recaptcha. Without it, I am getting error:

reCAPTCHA has already been rendered in this element

I was trying to do according to Firebase documentation

grecaptcha.reset(window.recaptchaWidgetId);

// Or, if you haven't stored the widget ID:

window.recaptchaVerifier.render().then(function(widgetId) { grecaptcha.reset(widgetId); }

but it does not work in my code. I dont have grecaptcha implemented. I tried to add it with react-grecaptcha, but it did not work.

Could someone give me a hint how to reset recaptcha after each error, please?

  state = {
    phone: "",
    confirmationResult: {},
  };

  handleClick = () => {
    const recaptchaVerifier = new firebase.auth.RecaptchaVerifier(
      "sign-in-button",
      {
        size: "invisible",
      }
    );
    firebase
      .signInWithPhoneNumber(`+${this.state.phone}`, recaptchaVerifier)
      .then((confirmationResult) => {
        this.setState({ confirmationResult });
      })
      .catch((error) => {
        // Error; SMS not sent
        // Handle Errors Here
        window.alert(`${error.code}, ${error.message}`);
        recaptchaVerifier.reset(); // How can I do that?
      });
  };
Andrzej Popek
  • 23
  • 1
  • 3
  • Hey and welcome to SO! I'm not an expert with FIrebase but aren't you looking for the `.clear()` method? https://firebase.google.com/docs/reference/js/firebase.auth.RecaptchaVerifier#clear – Pedro Filipe Jul 01 '20 at 17:26
  • Hello, thank you for your reply. When I try `.clear()` I am getting error object: `code: "auth/internal-error" message: "RecaptchaVerifier instance has been destroyed"` – Andrzej Popek Jul 01 '20 at 17:40

2 Answers2

1

I've been struggling with this problem for several days, maybe my answer will help someone.

    export const requestRecaptchVerifier = () => {
    window.recaptchaVerifier = new RecaptchaVerifier(
        "recapcha-container",
        {
            size: "invisible",
        },
        auth
    );
};

I then call signInWithPhone from another function and handle the error like this:

        await signInWithPhone(formik.values.phone)
        .then(() => {
            // ... my code
        })
        .catch(() => {
            window.recaptchaVerifier.recaptcha.reset();
            window.recaptchaVerifier.clear();
        });

All the difference in

window.recaptchaVerifier.recaptcha.reset()

And

window.recaptchaVerifier.clear()
Fox0x
  • 11
  • 4
0

I'm no expert but from the documentation and by talking with you in the comment section I think you need to pass a callback. Like this:

const recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
  'size': 'invisible',
  'callback': function(response) {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
   firebase
  .signInWithPhoneNumber(`+${this.state.phone}`, recaptchaVerifier)
  .then((confirmationResult) => {
    this.setState({ confirmationResult });
  })
  .catch((error) => {
    // Error; SMS not sent
    // Handle Errors Here
    window.alert(`${error.code}, ${error.message}`);
    recaptchaVerifier.reset();
  });
  }
});

Reference: https://firebase.google.com/docs/auth/web/phone-auth#use-invisible-recaptcha

Hope this helps!

Pedro Filipe
  • 995
  • 1
  • 8
  • 17
  • Thank you, you helped. The reason for my problem was that I didn't handle callbacks for recaptcha. I didn't fully understand documentation too, it was explained there. – Andrzej Popek Jul 02 '20 at 07:33