8

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>
    );
  }
}
Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
Vinay Sharma
  • 3,291
  • 4
  • 30
  • 66
  • Has anyone solved this yet @Vinay @Doug? I'm having the same issue. – Chris Eaheart Sep 05 '20 at 14:14
  • 1
    Hi @ChrisEaheart it still hasn’t been solved. I had raised a **GitHub Issue** and will suggest to keep looking for any updates over there: https://github.com/firebase/firebase-js-sdk/issues/3314 – Vinay Sharma Sep 06 '20 at 15:31
  • you can it here: [nextjs with firebase phone auth](https://stackoverflow.com/a/75156416/7956318) – sun sreng Jan 18 '23 at 08:28

2 Answers2

3

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);
}, []);
Ernest Okot
  • 880
  • 3
  • 8
  • 23
  • 1
    The `.verify()` callback is what I was looking for. I was using the `.render()` function instead but verify was what I needed, thanks! – James Hooper May 03 '22 at 07:57
2

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>
    );
  }

}
Tim
  • 12,318
  • 7
  • 50
  • 72
  • I don't think this pre-render is a nice solution for this as I can get this code working in Vanilla JS without it. For your reference you can check here: https://github.com/vinaysharma14/react-firebase/blob/master/src/App.tsx – Vinay Sharma Sep 13 '20 at 15:27