15

Due to my probable misuse of anonymous authentication (see How to prevent Firebase anonymous user token from expiring) I have a lot of anonymous users in my app that I don't actually want.

I can't see any way to bulk delete these users. Do I have to do it manually one-by-one? Is there anyway to use the API to access user accounts and manipulate them for users other than the current user?

Community
  • 1
  • 1
Matthew Gertner
  • 4,487
  • 2
  • 32
  • 54
  • I have a slightly different case than this, but I use async await to delete anonymous users that signed in last six month ago: https://stackoverflow.com/a/66837805/9605341 – sarah Mar 28 '21 at 02:10

10 Answers10

16

This code sample uses the Firebase Admin SDK for Node.js, and will delete any user that has no providerData, which means the user is anonymous:

function deleteAnonymousUsers(nextPageToken) {
 adminApp
    .auth()
    .listUsers(20, nextPageToken)
    .then(function(listUsersResult) {
      listUsersResult.users.forEach(function(userRecord) {
        if (userRecord.providerData.length === 0) { //this user is anonymous
         console.log(userRecord); // do your delete here
         adminApp.auth().deleteUser(userRecord.uid)
            .then(function() {
                console.log("Successfully deleted user");
            })
            .catch(function(error) {
                console.log("Error deleting user:", error);
            });
        }
      });
      if (listUsersResult.pageToken) {
        // List next batch of users.
        deleteAnonymousUsers(listUsersResult.pageToken);
      }
    })
    .catch(function(error) {
      console.log('Error listing users:', error);
    });
}
regretoverflow
  • 2,093
  • 1
  • 23
  • 45
9

There is no way in the Firebase Console to bulk-delete users.

There is no API to bulk-delete users.

But there is administrative API that allows you to delete user accounts. See https://firebase.google.com/docs/auth/admin/manage-users#delete_a_user

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
5

I just wanted to add a method I just used to (sort-of) bulk-delete. Mostly because I felt clever after doing it and I am not that clever.

I downloaded a mouse-automation application that lets you record your mouse clicks then replay it automatically. I just deleted almost 1000 users while playing the piano lol.

I used Macro Recorder and it worked like a charm. Just recorded a few iterations in the console of me deleting users, set it to repeat 500 times and walked away.

I know this isn't a very technical answer, but it saved me hours of monotonous mouse clicking so hopefully someone else looking for a way to bulk-delete will benefit from it as well. I hated the fact that there was no bulk-delete and really needed a way out of it. It only took about 20 manual deletes to realize there were apps that could do what I was doing.

Ryan
  • 1,988
  • 4
  • 21
  • 34
  • 1
    I posted answer which does this with few lines of code without any dependency https://stackoverflow.com/a/70917483/1353874 – miro Jan 30 '22 at 18:09
4

If you do not need to do it on a large scale and you want to delete some anonymous users from Firebase Console UI, but you are lazy to click on 250 users one-by-one, run the following code in your console (screen where table with users is shown):

rows = Array.from(document.querySelectorAll('td.auth-user-identifier-cell')).map(td => td.parentNode).filter((tr) => tr.innerText.includes('anonymous'))

var nextTick = null

function openContextMenu(tr) {
    console.log('openning menu')
    tr.querySelector('.edit-account-button').click()
    nextTick = deleteUser
}

function deleteUser() {
    console.log('deleting user')
    document.querySelector('.cdk-overlay-connected-position-bounding-box button:last-of-type').click()
    nextTick = confirmDelete
}

function confirmDelete() {
    console.log('confirming action')
    document.querySelector('.cdk-global-overlay-wrapper .confirm-button').click()
    nextTick = getUser
}

function getUser() {
    console.log('getting user')
    openContextMenu(rows.shift())
}

nextTick = getUser
step = 500
setInterval(() => {
    nextTick()
}, step)

It basically selects all rows which contain anonymous user and simulate you clicking the three dots, then clicking on delete account and as a last step it confirms action in the modal which appears.

Before running the script, select 250 rows per page in the table's footer. When all anonymous users are removed, you must manually go to next page and re run the script (or code in another "tick" which paginates for you).

It takes 1.5 second to delete one user (you can modify this with step variable, but I do not recommend go lower than 500ms - mind the UI animations).

It runs also in a tab in background so you can watch some YT in meantime :)

miro
  • 735
  • 8
  • 16
3

Update 2021:

I had around 10,000 anonymous users, and @regretoverflow's solution lead to exceeding the delete user quota. However, slightly tweaking the code to utilize the admin's deleteUsers([userId1, userId2, ...]) API works like a charm.

function deleteAnonymousUsers(nextPageToken: string | undefined) {
  firebaseAdmin
    .auth()
    .listUsers(1000, nextPageToken)
    .then(function (listUsersResult) {
      const anonymousUsers: string[] = [];
      listUsersResult.users.forEach(function (userRecord) {
        if (userRecord.providerData.length === 0) {
          anonymousUsers.push(userRecord.uid);
        }
      });

      firebaseAdmin
        .auth()
        .deleteUsers(anonymousUsers)
        .then(function () {
          if (listUsersResult.pageToken) {
            // List next batch of users.
            deleteAnonymousUsers(listUsersResult.pageToken);
          }
        })
    })
}
deleteAnonymousUsers(undefined);
  • I've used this before and it worked great, but now it fails with "uncaught synt ax Error: Missing initializer in const declaration". Thoughts? – GGizmos Dec 17 '22 at 00:27
2

There is a firebase-functions-helper package, that can help to delete firebase users in bulk.

// Get all users 
firebaseHelper.firebase
    .getAllUsers(100)    
    .then(users => {        
        users.map(user => {
            firebaseHelper.firebase
                .deleteUsers([user.uid]);          
        })   
    })

The code above will get 100 users, and delete all of them. If you don't pass the number, the default value is 1000. You can read the instruction on Github repository.

Dale Nguyen
  • 1,930
  • 3
  • 24
  • 37
  • This is still not a bulk delete, which purpose is to do a single transaction. The code of `deleteUsers()` just iterates over the list and deletes the items one by one. Same as any admin command. – mrj Jan 23 '20 at 09:56
1

I faced the same problem today then I found Firebase Admin SDK. I am using Node.js which is very easy to install, so you can try the following code. It is not a complete answer I know but one can build its own script/application to delete stored uids. Yet, there is no way to retrieve a list, so you have to build one somehow every time you create an anonymous account.

First, download your 'serviceAccountKey.json' which can be done through the Firebase Console (Project Settings). In my case I renamed the download file to a more friendly name and saved to documents folder.

console.firebase.google.com/project/yourprojectname/settings/serviceaccounts/adminsdk

Useful links:

Then, play around using Windows cmd.exe or any other shell. The 'npm install -g' installs firebase-admin globally in your machine.

$ npm install firebase-admin -g
$ node
> var admin = require("firebase-admin");
> admin.initializeApp({
  credential: admin.credential.cert("./documents/yourprojectname-firebase-admin.json"),
  databaseURL: "https://yourprojectname.firebaseio.com"
});
> var db = admin.database();
// Of course use an existent UID of your choice
> admin.auth().getUser('2w8XEVe7qZaFn2ywc5MnlPdHN90s').then((user) => console.log
(user))
> admin.auth().deleteUser('2w8XEVe7qZaFn2ywc5MnlPdHN90s').then(function() {
    console.log("Successfully deleted user");
  }).catch(function(error) {
    console.log("Error deleting user:", error);
  });

// To get access to some key/values in your Database:
> var ref = db.ref("users/1234");
> ref.once("value", function(snapshot) {
  console.log(snapshot.val());
});
nloewen
  • 1,279
  • 11
  • 18
Roque
  • 359
  • 4
  • 8
1

I had the same problem. because Firebase doesn't provide any API to delete bulk users but this is how I have deleted all anonymous users.

Download all the users as json via firebase tool
firebase auth:export users --format=json
https://firebase.google.com/docs/cli/auth#file_format

You can write a firebase cloud function to trigger or write a action method to trigger

import the json file in to your file,

const Users = require('./users.json'); // ES5 <br>
import Users from './users.json'); // ES6 <br>

normally anonymous user doesn't have email so it is easy to delete the record which doesn't have email id

Users.users.map(user => {
    setTimeout(() => {
      admin.auth().deleteUser(user.localId).then(() =>{
        console.log("Successfully deleted user");
      })
      .catch((error) => {
        console.log("Error deleting user:", error);
      });
    }, 20000);
  });

Don't try to reduce the timeout second. It will throw below error

Error deleting user: { Error: www.googleapis.com network timeout. Please try again.
Aathi
  • 2,599
  • 2
  • 19
  • 16
  • your going to delete facebook accounts which have phone number as user ID , aren't you ? – j2emanue Apr 04 '18 at 06:32
  • as @j2emanue mentions and I noticed in trying to export statistics for providers (https://github.com/ddikman/firebase-provider-stats/) the data in the export doesn't clearly state each provider, so be careful with this. Not only are phone number registrations missing but Apple IDs as well – Almund Apr 13 '22 at 07:44
1

I was writing myself a firebase functions function with Firebase auth. It works like a charm for me and i can clean with one API call.

// Delete all Anon User
exports.deleteUser = functions.https.onRequest(async (req, res) => {
    const admin = require("firebase-admin");    

    //initialize auth
    admin.initializeApp(); 
    //create auth instance
    const auth = admin.auth();
    //Get the list of all Users
    const allUsers = await auth.listUsers();  
    //Identify the Anon User give other user null
    const allUsersUID = allUsers.users.map((user) => (user.providerData.length === 0) ? user.uid : null);
    //remove the null
    const filteredallUsersUID = allUsersUID.filter(e => e !== null)
    //delete and answer the API call
    return auth.deleteUsers(filteredallUsersUID).then(() => res.send("All Anon-User deleted"));

  });

With this you can just simply call your API URL https://[Your_API_URL]/deleteUser

Just require basic knowledge of Firebase Functions. I assume this could be also added to a cron job.

Bliv_Dev
  • 557
  • 7
  • 19
  • 1
    from the documentation in here https://firebase.google.com/docs/auth/admin/manage-users#list_all_users . using listUsers() without recursive will only retrieve 1000 account, say if the first 1000 no longer have anonymous accounts, then we will never delete any account afterwards – sarah Mar 28 '21 at 00:38
  • Good feedback ! did not make it to so many users ... but i will get back to my script when i do ;) – Bliv_Dev Apr 03 '21 at 09:21
  • 1
    maybe this will help you a little bit: stackoverflow.com/a/66837805/9605341 :) – sarah Apr 04 '21 at 04:08
0

The Firebase Admin SDK can also delete multiple users at once.

Here is Node.js sample.

admin.auth().deleteUsers([uid1, uid2, uid3])
  .then(deleteUsersResult => {
    console.log('Successfully deleted ' + deleteUsersResult.successCount + ' users');
    console.log('Failed to delete ' +  deleteUsersResult.failureCount + ' users');
    deleteUsersResult.errors.forEach(err => {
      console.log(err.error.toJSON());
    });
  })
  .catch(error => {
    console.log('Error deleting users:', error);
  });

Notice: there is a limitation as list all users. The maximum number of users allowed to be deleted is 1000 per batch.

Leo Lee
  • 1
  • 3