Can I use the auth:import and auth:export tools with the Firebase Auth Emulator?

I would like to preload the firebase auth emulator with my test user accounts whenever it starts up, the same way I do for the Firestore emulator with its import/export options. I tried using auth:import and auth:export while my emulators were running but it connected to our actual dev firebase project, and not the emulators. Is there anyway to run auth:import and auth:export against the auth emulator?

For reference, I am referring to these commands (https://firebase.google.com/docs/cli/auth) and this emulator (https://firebase.google.com/docs/emulator-suite/connect_auth).


Solution 1:

The ability to do this has now been added to the firebase tools

The older answers still work and may be useful

https://github.com/firebase/firebase-tools/releases/tag/v9.1.0

Support emulators:export and import for Auth Emulator (#2955).

https://github.com/firebase/firebase-tools/pull/2955

firebase help auth:import
Usage: firebase auth:import [options] [dataFile]

import users into your Firebase project from a data file(.csv or .json)

Options:
  --hash-algo <hashAlgo>               specify the hash algorithm used in password for these accounts
  --hash-key <hashKey>                 specify the key used in hash algorithm
  --salt-separator <saltSeparator>     specify the salt separator which will be appended to salt when verifying password. only used by SCRYPT now.
  --rounds <rounds>                    specify how many rounds for hash calculation.
  --mem-cost <memCost>                 specify the memory cost for firebase scrypt, or cpu/memory cost for standard scrypt
  --parallelization <parallelization>  specify the parallelization for standard scrypt.
  --block-size <blockSize>             specify the block size (normally is 8) for standard scrypt.
  --dk-len <dkLen>                     specify derived key length for standard scrypt.
  --hash-input-order <hashInputOrder>  specify the order of password and salt. Possible values are SALT_FIRST and PASSWORD_FIRST. MD5, SHA1, SHA256, SHA512, HMAC_MD5, HMAC_SHA1, HMAC_SHA256, HMAC_SHA512 support this flag.
  -h, --help                           output usage information

Solution 2:

Thanks @alex-egli this was very helpful

Here's my version which is based on yours with 3 small changes

  1. avoid an eslint warning https://eslint.org/docs/rules/no-await-in-loop
    (I don't think your code is bad here and the warning could be muted)

  2. add in a check that this is being run on the emulator

  3. added user display name

exports.populateAuthUsers = functions.https.onRequest(async (req, res) => {
  if (!process.env["FUNCTIONS_EMULATOR"]) {
    return res
      .status(403)
      .send("ACCESS DENIED. This function is ONLY available via an emulator");
  }
  const users = [
    {
      uid: "user1",
      displayName: "one Local Admin",
      email: "[email protected]",
      password: "password",
    },
    {
      uid: "user2",
      displayName: "two Local Admin",
      email: "[email protected]",
      password: "password",
    },
    // put all test users you want populated here
  ];

  const results = [];
  const promises = [];
  for (let user of users) {
    let promise = admin
      .auth()
      .createUser(user)
      .then((result) => {
        return result;
      })
      .catch((error) => {
        return error.message; // continue on errors (eg duplicate users)
      });

    promises.push(promise);
  }
  await Promise.all(promises).then((result) => {
    results.push(result);
    return;
  });
  res.header("Content-type", "application/json");
  return res.status(200).send(JSON.stringify(results));
});

Solution 3:

Since firebase confirmed this is not supported I used a cloud function instead to do this. I first exported the users I would want to be loaded on startup into a json format, then I run this cloud function everytime I restart the emulators:

exports.populateAuthUsers = functions.https.onRequest(async (req, res) => {

  try {
    admin.initializeApp();
    
    const users = [
      { uid: "user1", email: "[email protected]", password: "password" },
      // put all test users you want populated here
    ];

    const results = [];
    for (let user of users) {
      const result = await admin.auth().createUser(user);
      results.push(result);
    }

    return res.status(200).send(results);
  } catch (error) {
    console.error('Error: ', error);
    return res.status(500).send(error);
  }
});

It only takes a couple seconds to run even with a few hundred users. Just make sure to never deploy this to any actual firebase environments! For local use only.