Vinay Sharma
Vinay Sharma

Reputation: 3777

Firebase: Invisible reCaptcha does not work in React JS

Overview

Hi, I am using Firebase's invisible reCaptcha for phone number authentication in my React JS application. As per the documentation of Firebase you need to provide id (e.g. sign-in-button) of the button which handles submit of login form.

Expected Behaviour

Once user click on that button, Firebase's invisible reCaptcha should kick in and checks if it has been resolved by the user or not. If reCaptcha is resolved, a callback provided by new firebase.auth.RecaptchaVerifier('...', {}) will be fired. In that callback we are supposed to send an OTP code to user's phone number.

Issue

What's the happening is that the callback is not being fired unless the OTP isn’t sent on submit of the login form which doesn’t make sense because sending OTP needs to handled by the callback provided by invisible reCaptcha and not by sending the OTP with onSubmit of the form.

Version

"firebase": "^7.15.1",

Code

import React, { Component } from 'react';

import firebase from 'firebase/app';
import 'firebase/auth';

firebase.initializeApp({
  apiKey: 'xxx',
  authDomain: 'xxx',
  databaseURL: 'xxx',
  projectId: 'xxx',
  storageBucket: 'xxx',
  messagingSenderId: 'xxx',
  appId: 'xxx',
  measurementId: 'xxx',
});

class App extends Component {
  componentDidMount() {
    window.reCaptchaVerifier = new firebase.auth.RecaptchaVerifier('login-button', {
      size: 'invisible',
      callback: () => {
        // callback is not being fired automatically
        // but after the OTP has been sent to user's
        // phone number which makes this callback useless
        // as opposed to Firebase's documentation
      },
    });
  }

  handleSubmit = event => {
    event.preventDefault();

    firebase
      .auth()
      .signInWithPhoneNumber('+1 XXX-XXX-XXXX', window.reCaptchaVerifier)
      .then(confirmationResult => {
        window.confirmationResult = confirmationResult;
      })
      .catch(() => {});
  };

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <input />
        <button id="login-button">Submit</button>
      </form>
    );
  }
}

Upvotes: 9

Views: 7725

Answers (2)

Ernest Okot
Ernest Okot

Reputation: 986

This is what I'm using, seems to work well

const [token, setToken] = useState("");

useEffect(() => {
  new firebase.auth.RecaptchaVerifier("request-otp", { size: "invisible" })
    .verify()
    .then(setToken);
}, []);

Upvotes: 7

Tim
Tim

Reputation: 13058

Usually, reCAPTCHA needs to be rendered before it is used. So, for example, the following code works. The only modifications from the code in the question are:

  • reCAPTCHA is rendered explicitly in componentDidMount
  • form's onSumbit is not used therefore (it actually never fires in this scenario, because reCAPTCHA callback processes the submit event instead)

Working solution with pre-render:

class App extends Component {
  componentDidMount() {
    const reCaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
      size: 'invisible',
      callback: function (response) {
        console.log('It works!');
      },
    });
    reCaptchaVerifier.render();
  }

  render() {
    return (
      <form>
        <input />
        <button id="sign-in-button">Submit</button>
      </form>
    );
  }

}

Upvotes: 3

Related Questions