Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase phone number authentication with Vue.js does not work

I am building a new Vue.js app based on the Webpack template. I have a /sign-in route that loads a component called SignIn. I am trying to use Firebase Phone Number authentication using the Firebase SDK to authenticate my users.

I've installed Firebase with npm install firebase and initialized it in my main.js file like this:

/src/main.js

import firebase from 'firebase';

import Vue from 'vue';
import App from './App';
import router from './router';

Vue.config.productionTip = false;

// Initialize Firebase
const config = {
  apiKey: 'MY_API_KEY',
  authDomain: 'MY_PROJECT.firebaseapp.com',
  databaseURL: 'https://MY_PROJECT.firebaseio.com',
  projectId: 'MY_PROJECT_ID',
  storageBucket: 'MY_PROJECT.appspot.com',
  messagingSenderId: 'MY_SENDER_ID',
};

firebase.initializeApp(config);

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  template: '<App/>',
  components: { App },
});

My credentials are redacted for security in the above example.

When the user is on /sign-in, this is the component that they see:

/src/components/pages/SignIn.vue

<template>
  <div>
    <!-- Number Input Form -->
    <div v-if="showNumberInput">
      <form v-on:submit.prevent>
        <div class="form-group">
          <input type="text" class="form-control form-control-lg" v-model="numberInputForm.number" placeholder="Phone number" required>
        </div>
        <div class="form-group">
          <button type="submit" id="get-sign-in-code" class="btn btn-block btn-lg success theme-accent">{{ getSignInCodeButton.text }}</button>
        </div>
      </form>
    </div>

    <!-- SMS Verification Form -->
    <div v-if="showCodeInput">
      <form>
        <div class="form-group">
          <input type="text" class="form-control form-control-lg" value="9944" placeholder="Verification Code" required>
        </div>
        <div class="form-group">
          <a href="javascript:void" class="btn btn-block btn-lg success theme-accent" @click="signIn">{{ signInButton.text }}</a>
        </div>
      </form>
    </div>
  </div>
</template>

<script>
import firebase from 'firebase';

export default {
  name: 'SignIn',

  data() {
    return {
      // UI States
      showNumberInput: true,
      showCodeInput: false,

      // Forms
      numberInputForm: {
        number: '',
      },

      // Buttons
      getSignInCodeButton: {
        text: 'Get sign in code',
      },
      signInButton: {
        text: 'Sign in',
      },
    };
  },

  mounted() {
    const self = this;

    // Start Firebase invisible reCAPTCHA verifier
    window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('get-sign-in-code', {
      'size': 'invisible',
      'callback': (response) => {
        // reCAPTCHA solved, allow signInWithPhoneNumber.
        self.sendSMS();
      }
    });
  },

  methods: {
    /**
     * Sends the user an SMS-verification code using Firebase auth
     *
     * @see https://firebase.google.com/docs/auth/web/phone-auth
     */
    sendSMS() {
      const self = this;

      self.getSignInCodeButton = {
        showSpinner: true,
        text: 'Sending SMS..',
        disabled: true,
      };
    },


    /**
     * Authenticates the user with Firebase auth
     */
    signIn() {
      // Redirect the user to the authenticated page
    },
  },
};
</script>

As you can see, I have two forms in the template - one to capture the phone number and another to allow the user to enter the verification code. I am toggling the visibility of these forms programmatically.

When the component mounts, I am calling the Firebase reCAPTCHA verifier and passing the ID of the submit button ("get-sign-in-code" in this case). However, when I click the button, nothing happens. I don't see the reCAPTCHA XHR in my dev tools network tab.

Could this be because the button is being inserted into the DOM dynamically and firebase.auth.RecaptchaVerifier() cannot detect it when I pass the ID when the component mounts? How do I resolve this? Could I use $el or some other Vue.js method to get the reCAPTCHA verifier to work? Thanks.

UPDATE

I was able to get this script to work by adding the following lines to the mounted() event:

window.recaptchaVerifier.render().then((widgetId) => {
  window.recaptchaWidgetId = widgetId;
});

This is how my mounted() method looks like now:

mounted() {
  const self = this;

  // Start Firebase invisible reCAPTCHA verifier
  window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('get-sign-in-code', {
    size: 'invisible',
    callback: () => {
      // reCAPTCHA solved, allow signInWithPhoneNumber.
      self.sendSMS();
    },
  });

  window.recaptchaVerifier.render().then((widgetId) => {
    window.recaptchaWidgetId = widgetId;
  });
},

This however cause a new issue - the script now adds a randomly positioned "Protected by reCAPTCHA" badge that I'd like to get rid off. Is there any way to get this script to work without showing the badge?

like image 665
JackH Avatar asked Jan 18 '18 13:01

JackH


People also ask

How do I add my phone number to Firebase authentication?

In the Firebase console, open the Authentication section. In the Sign in method tab, enable the Phone provider if you haven't already. Open the Phone numbers for testing accordion menu. Provide the phone number you want to test, for example: +1 650-555-3434.

How do I authenticate a phone number?

Phone-based authentication involves sending a one-time password (OTP) to a user over a separate communication channel (e.g. SMS, MMS, WhatsApp, Facebook Messenger, Viber or even voice) from the IP channel (internet) used by the application, providing security in case the IP channel is compromised.

How do I use Firebase authentication in Vue Cinema?

Setting up Firebase Auth Here, click on Add new project and name the project vue-firebase-auth . You will be redirected to the project's dashboard. On the dashboard, click on the web icon to register your front-end app. Name your app vuex-firebase-authentication and click on Register app .


1 Answers

I guess it is late to answer. But I see in your code when mounted() hook appeared you call sendSMS() function in recaptchaVerifier after callback. But when on subbitting first button which is:

<button type="submit" id="get-sign-in-code" class="btn btn-block btn-lg success theme-accent">{{ getSignInCodeButton.text }}</button>

no function showed to call on submit or on click. I guess you would update your button to react clicking on it like below: change is in form tag that showing which function to call on submit form.

<div v-if="showNumberInput">
  <form v-on:submit.prevent="sendSMS">
    <div class="form-group">
      <input type="text" class="form-control form-control-lg" v-model="numberInputForm.number" placeholder="Phone number" required>
    </div>
    <div class="form-group">
      <button type="submit" id="get-sign-in-code" class="btn btn-block btn-lg success theme-accent">test</button>
    </div>
  </form>
</div>
like image 193
WebMan Avatar answered Oct 01 '22 03:10

WebMan