javascriptfirebasevue.jsgoogle-cloud-platformgoogle-cloud-functions

httpsCallable is not a function when calling a Firebase function


I'm trying to implement a role-based authentication using Firebase auth and Firebase functions. Right now I have a registration form that is working as supposed and now I'm trying to add a form that you submit an email that calls the Firebase function that will attach a custom claim to a user. I already added my function to Firebase via the terminal and I'm calling functions on my project but whenever I submit the form with the email I get a httpsCallable is not a function error.

Here are my files:

index.js inside functions folder

const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();

exports.addAdminRole = functions.https.onCall((data, context) => {
  //get user and add custom claim (admin)
  return admin
    .auth()
    .getUserByEmail(data.email)
    .then(user => {
      return admin.auth().setCustomUserClaims(user.uid, {
        admin: true
      });
    })
    .then(() => {
      return {
        message: `Success! ${data.email} has been made admin`
      };
    })
    .catch(err => {
      return err;
    });
});

My firebaseInit.js config file where I call everything firebase related

import firebase from "firebase/app";
import "firebase/firestore";
import "@firebase/functions";
import firebaseConfig from "./firebaseConfig";
const firebaseApp = firebase.initializeApp(firebaseConfig);

export const fc = firebase.functions();
export const db = firebase.firestore();
export const fv = firebase.firestore.FieldValue;

export default firebaseApp.firestore();

And my Vue component where the form is

<template>
  <div class="home">
    <h3>Welcome to Site</h3>

    <h3>Add user to admin</h3>
    <div class="row">
      <form @submit.prevent="addAdmin()" class="col s12">
        <div class="row">
          <div class="input-field col s12">
            <input id="email" type="email" class="validate" v-model="email" />
            <label for="email">Email</label>
          </div>
        </div>
        <button type="submit" class="btn">Submit</button>
        <router-link to="/members" class="btn grey">Cancel</router-link>
      </form>
    </div>
  </div>
</template>

<script>
import firebase from "firebase/app";
import fc from "../data/firebaseInit";
export default {
  name: "home",
  data() {
    return {
      email: ""
    };
  },
  methods: {
    addAdmin() {
      const addAdminRole = fc.httpsCallable("addAdminRole");
      addAdminRole(this.email).then(result => {
        console.log(result);
      });
    }
  }
};
</script>

Can someone shed a light on why I'm getting this error? Am I forgetting to import something firebase related?


Solution

  • Your problem comes from the fact that by doing

    export const fc = firebase.functions();
    export const db = firebase.firestore();
    export const fv = firebase.firestore.FieldValue;
    
    export default firebaseApp.firestore();
    

    in your firebaseInit.js file, you aren't exporting fc (nor fv by the way)

    The following should work

    import firebase from "firebase/app";
    import "firebase/firestore";
    import "firebase/functions";   // <-- Note that the @ was removed
    import firebaseConfig from "./firebaseConfig";
    const firebaseApp = firebase.initializeApp(firebaseConfig);
    
    const fc = firebase.functions();
    const db = firebase.firestore();
    const fv = firebase.firestore.FieldValue;
    
    export { fc, db, fv };
    

    Then, in your component you do:

    import {fc, db, fv} from "../data/firebaseInit";
    
    //....
    

    Or the following it you only need fc and db, for example:

    import {fc, db} from "../data/firebaseInit";
    
    //....