Skip to content
Advertisement

Delete user using firebase Admin SDK

How do I delete a user from my admin panel using the firebase Admin SDK? I’m getting this error when trying to delete it:

Uncaught (in promise) ReferenceError: uid is not defined at eval (ManageCustomer.vue?b113:262)

What am I doing wrong?

This is my code in index.js from functions

 const functions = require("firebase-functions");
    const admin = require("firebase-admin");
    admin.initializeApp();
    const db = admin.firestore();
    
    exports.AddUserRole = functions.auth.user().onCreate(async (authUser) => {
      if (authUser.email) {
        const customClaims = {
          //admin: true,
          customer: true,
        };
        try {
          var _ = await admin
            .auth()
            .setCustomUserClaims(authUser.uid, customClaims);
          return db
            .collection("roles")
            .doc(authUser.uid)
            .set({
              email: authUser.email,
              role: customClaims,
            });
        } catch (error) {
          console.log(error);
        }
      }
    });
    
    exports.deleteUser = functions.https.onCall(async (data, context) => {
      if (!context.auth.token.admin) return    
      try {
        var _ = await admin
          .auth()
          .deleteUser(uid)
          .then(() => {
            console.log("Successfully deleted user");
          })
          .catch((error) => {
            console.log("Error deleting user:", error);
          });
      } catch (error) {
        console.log("error deleting user", error);
      }
    });

Here is my client side code

   <template>
  <div class="manage-customer">
    <br />
    <div>
      <h2>Customer</h2>
      <br />

      <section>
        <div class="">
          <div class="column">
            <div>
              <div class="header" style=" font-weight: bold;">
                Customer Info
              </div>
              <router-link to="/admin/new-user" class="btn" href="#">
                New User</router-link
              >

              <table class="table table-users" cellspacing="0">
                <thead>
                  <tr style=" text-align: center;">
                    <th
                      style="background: var(--primary); color: var(--secondary); width:180px "
                    >
                      User Id
                    </th>
                    <th
                      style="background: var(--primary); color: var(--secondary); width:180px"
                    >
                      Username
                    </th>
                    <th
                      style="background: var(--primary); color: var(--secondary); width:120px"
                    >
                      Email
                    </th>
                    <th
                      style="background: var(--primary); color: var(--secondary); width:150px"
                    >
                      Phone
                    </th>
                    <th
                      style="background: var(--primary); color: var(--secondary); width:220px"
                    >
                      Address
                    </th>
                    <th
                      style="background: var(--primary); color: var(--secondary); width:60px"
                    >
                      Postcode
                    </th>
                    <th
                      style="background: var(--primary); color: var(--secondary); width:170px; "
                    >
                      Action
                    </th>
                  </tr>
                </thead>
                <tbody>
                  <tr v-for="profile in profiles" :key="profile.id">
                    <td data-label="Id" style="width: 160px;">
                      {{ profile.id }}
                    </td>
                    <td data-label="DisplayName" style="width: 150px">
                      {{ profile.displayName }}
                    </td>
                    <td data-label="Email" style="width: 150px">
                      {{ profile.email }}
                    </td>
                    <td data-label="Phone" style="width: 100px">
                      {{ profile.phone }}
                    </td>
                    <td data-label="Address" style="width: 250px">
                      {{ profile.address }}
                    </td>
                    <td data-label="Postcode" style="width: 70px">
                      {{ profile.postcode }}
                    </td>
                    <td
                      style="width:170px; display:inline-flex;"
                      data-label="Action"
                    >
                      <button
                        @click="editProfile(profile)"
                        class="edit-product"
                        style=" "
                      >
                        Edit
                      </button>

                      <button
                        class="delete-product"
                        @click="deleteProfile(profile)"
                        style=""
                      >
                        Delete
                      </button>
                    </td>
                  </tr>
                </tbody>
              </table>

              <br />
            </div>
          </div>
        </div>
      </section>
      <modal
        name="profiles"
        style="top: 10px; margin: 0 auto;"
        height="80%"
        width="65%"
        :adaptive="true"
      >
        <div class="container">
          <div class="modal-body-product">
            <form style=" width: 90% !important; border: 0;  box-shadow: none;">
              <div>
                <span @click="hide" class="close">✖</span>
              </div>
              <!-- <h3 id="productLabel">Add Profile</h3> -->
              <h3 id="productLabel" style="margin-bottom: 1.5rem;">
                EDIT PROFILE
              </h3>

              <div class="form-group">
                <label for="">Username:</label>
                <input
                  type="text"
                  class="form-control"
                  placeholder="Username"
                  v-model.lazy="profile.displayName"
                />
              </div>
              <div class="form-group">
                <label for="">Phone:</label>
                <input
                  name="description"
                  class="form-control"
                  placeholder="Phone"
                  v-model.lazy="profile.phone"
                />
              </div>
              <div class="form-group">
                <label for="">Address:</label>
                <input
                  type="text"
                  placeholder="Address"
                  v-model.lazy="profile.address"
                  class="form-control"
                />
              </div>

              <div class="form-group">
                <label for="">Postcode:</label>
                <input
                  type="text"
                  placeholder="Postcode"
                  v-model.lazy="profile.postcode"
                  class="form-control"
                />
              </div>
              <div class="modal-footer">
                <!-- <button
                  class="btn"
                  type="button"
                  @click.prevent="addProfile()"
                  @click="hide"
                >
                  Save
                </button> -->
                <br />
                <button class="btn" type="button" @click="updateProfile()">
                  Apply changes
                </button>
              </div>
            </form>
          </div>
        </div>
      </modal>
    </div>
    <router-view></router-view>
  </div>
</template>
<script>
import firebase from "firebase";
// const admin = require("firebase-admin");
// admin.initializeApp();
// const db = admin.firestore();
import Swal from "sweetalert2";
window.Swal = Swal;

const Toast = Swal.mixin({
  toast: true,
  position: "top-end",
  showConfirmButton: false,
  timer: 3000,
});

window.Toast = Toast;

export default {
  name: "Dashboard",
  data() {
    return {
      users: [],
      user: "",
      roles: [],
      profiles: [],
      profile: {
        id: null,
        displayName: null,
        phone: null,
        address: null,
        postcode: null,
      },
      activeItem: null,
    };
  },
  firestore() {
    return {
      profiles: firebase.firestore().collection("profiles"),
      roles: firebase.firestore().collection("roles"),
    };
  },

  created() {
    var self = this;
    firebase.auth().onAuthStateChanged((user) => {
      self.user = user;
    });
    this.users = [];
    firebase
      .firestore()
      .collection("roles")
      .get()
      .then((snap) => {
        snap.forEach((doc) => {
          var user = doc.data();
          user.id = doc.id;
          console.log("🌿", doc.data());
          if (!user.role.admin) this.users.push(user);
        });
      });
  },
  methods: {
    // addNew() {
    //   this.$router.push("/admin/new-user");
    // },
    hide() {
      this.$modal.hide("profiles");
    },
    editProfile(profile) {
      // this.modal = "edit";
      this.profile = profile;
      this.activeItem = profile.id;
      this.$modal.show("profiles");
    },
    updateProfile() {
      this.$firestore.profiles.doc(this.profile.id).update(this.profile);
      Toast.fire({
        icon: "success",
        title: "Profile updated successfully",
      });
      this.$modal.hide("profiles");
    },
    deleteProfile(doc) {
      Swal.fire({
        title: "Are you sure?",
        text: "You won't be able to revert this!",
        icon: "warning",
        showCancelButton: true,
        confirmButtonColor: "#3085d6",
        cancelButtonColor: "#d33",
        confirmButtonText: "Yes, delete it!",
      }).then((result) => {
        if (result.value) {
          this.$firestore.profiles.doc(doc.id).delete();
          // console.log(doc.id);
          this.$firestore.roles.doc(doc.id).delete();
          const uid = this.profile.id;

          var deleteUser = firebase.functions().httpsCallable("deleteUser");
          deleteUser({ uid }) // not deleteUser(uid)
            .then((result) => {
              console.log("User delete successfully", result);
            });

          Toast.fire({
            icon: "success",
            title: "Deleted successfully",
          });
        }
      });
    },
   
  },
};
</script>

Advertisement

Answer

You are not accessing the UID in your cloud function from the data object.

exports.deleteUser = functions.https.onCall(async (data, context) => {
      if (!context.auth.token.admin) return   
      const {uid} = data;
      if (!uid) return {error: "Please enter an UID"} 
      try {
        // return the promise from here
        await admin.auth().deleteUser(uid)
        await admin.firestore().collection("profiles").doc(uid).delete()
        console.log("Successfully deleted user");
        return {data: "User deleted"}   
      } catch (error) {
        console.log("error deleting user", error);
        return {error}
      }
    });

Also try passing the UID from Vue app in an object as shown in the documentation.

const uid = "uidOfUserToBeDeleted"

var deleteUser = firebase.functions().httpsCallable("deleteUser");
deleteUser({uid}) // not deleteUser(uid)
  .then((result) => {
    console.log("User delete successfully", result);
  })

However, the issue is on your frontend. Where is uid defined? In the example above I have hard coded it, make sure you fetch the UID from your input field if it is an admin that is trying to delete user.

Is the doc.id the UID of user to be deleted? If yes, then you should call function like this deleteUser(doc.id)

Advertisement