firebase-tools: Emulator export does not save created auth users

[REQUIRED] Environment info

firebase-tools: 8.14.0

Platform: macOS

[REQUIRED] Test case

firebase emulators:start --export-on-exit="./my-local-dump"

Then add a user to the Auth emulator then exit by sending a SIGINT.

firebase emulators:start --import="./my-local-dump"

Checking auth emulator again, we see the user we just created is gone.

[REQUIRED] Steps to reproduce

See above.

[REQUIRED] Expected behavior

Auth users added via the emulator are saved in the emulator export.

[REQUIRED] Actual behavior

The user is lost, it is not saved in the emulator export.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 30
  • Comments: 30 (10 by maintainers)

Most upvoted comments

For anyone waiting for this feature it will be included in the next release of firebase-tools!

It would be great to be able to define it in firebase.json like

{
  "emulators": {
    "ui": {
      "enabled": true,
      "host": "localhost",
      "port": 4000
    },
    "auth": {
      "data": "./.firebase/auth"
    }
  }
}

@bradleymackey @IsaiahByDayah thanks for trying out the Auth emulator right away! Yes this is on the roadmap for sure.

Shipped in v9.1.0!

Also, remember that you can create users with email+password / phone using the Node.js Admin SDK with UIDs of your choice, which comes in handy when matching database records in other emulators.

Keeping a setup script should unblock you from testing for now. And stay tuned while we work on import/exports!

At the moment i wrote a script to setup my user before tests, or I run it after starting the Emulator:

const { auth } = require('./emulator-admin');

(async () => {
  await auth.createUser({
    uid: 'ID',
    email: 'test@yourdomain.com',
    password: 'pwd',
    displayName: 'User Name',
  });

  console.log('User created successfully');
  process.exit();
})();

The “emulator-admin” script is a simple setup where I initialize an admin app with references to the emuulator’s endpoints

I was able to work around this by setting up a script that recreates users with the same UID. In our app, we have a users collection which stores additional user data.

I modified a onUserWrite trigger we already have to store the user email in the user collection (only when using the emulator).

const functions = require('firebase-functions');
const admin = require('firebase-admin');

const throwsHttpError = require('./throwsHttpError');


exports.onUserWrite = fn.firestore.document('users/{userId}').onWrite(async (change, context) => {
	const db = admin.firestore();
	const newValue = change.after.data();


	try {
                // do our regular stuff user data.

		/**
		 * Due to a limitation in firebase auth emulator where users are
		 * not persisted, we store the users email in the user collection
		 * to allows us to recreate user accounts when bootstrapping the emulator.
		 */
		if (process.env.FUNCTIONS_EMULATOR === 'true') {
			const user = await admin.auth().getUser(userId);
			await userDoc.update({ emulator_user_email: user.email });
		}
	} catch (ex) {
		throwsHttpError('unkown', ex.message);
	}
});

Then in a script called setup-emulator.js we do the following:

const admin = require('firebase-admin');
const readline = require('readline');

const rl = readline.createInterface({
	input: process.stdin,
	output: process.stdout,
});

admin.initializeApp({ projectId: 'YOUR_PROJECT_ID' });

(async () => {
	const auth = admin.auth();
	const db = admin.firestore();

	const usersSnapshot = await db.collection('users').get();
	usersSnapshot.forEach((doc) => {
		const data = doc.data();

		if (data.emulator_user_email) {
			auth.createUser({
				uid: doc.id,
				email: data.emulator_user_email,
				password: '123456',
				displayName: data.userName,
			});
		}
	});
        // used to keep firebase emulator alive
	rl.question('Hit CTRL+C to close'  () => {});
})();

This is the command we run to start the emulator:

FIREBASE_AUTH_EMULATOR_HOST=localhost:9099 firebase use default && firebase emulators:exec 'node ./functions/setup-emulator.js' --import=./save-data --export-on-exit --ui

The only caveat is that passwords are always reset.

@Joebayld You’d want it to be a Node.js script that you run every time you start the Auth Emulator, since Admin privileges are required to create with a fixed UID. For example, firebase emulators:exec 'node ./your-setup-script.js && node ./your-test-script.js'. For interactive development, you can replace node ./your-test-script.js with read (or pause on Windows), and you can add --ui after emulators:exec to start the Emulator UI.

We know this is not ideal and we’re committed to add support for import/exports just like the other emulators. Once we have that, the tricks above will only be required for more involved setups that cannot be covered with imports.

It would be great if we could get the auth export from the emulator to handle Google/FB/etc accounts so that they show right back up on import. Excited for this it will make development a lot easier for me every time I stop and start up the emulator. Thanks!

@tudor07 yes, hence this ticket

@Joebayld oh nice catch on the second issue! I think both are fixed here: https://github.com/firebase/firebase-tools/pull/2986

@Joebayld nope that sounds like a bug to me! But I can already in my head see why that went wrong 😃 I’ll get a fix together.

@Joebayld we actually have an API (not documented yet, but stable) in the emulators that lets you temporarily disable background triggers. This API exists in the emulator hub which is a small server that runs inside the Firebase CLI for emulate orchestration. This normally starts up at port 4400.

Here’s some pseudocode:

# Disable all non-HTTP functions triggers
HTTP PUT http://localhost:4400/functions/disableBackgroundTriggers

# Add your auth users in this middle period
# ...

# Enable all non-HTTP functions triggers
HTTP PUT http://localhost:4400/functions/disableBackgroundTriggers

So you can just make two PUT requests in your setup script, one at the start and one at the end, to add your users without firing any functions.

🙋‍♂️ waiting for this as well. Thanks so much for the work you do, Emulator Suite is awesome!

@yuchenshi, when you get the time would you be able to provide an example “setup script” that can use the Admin SDK to create users? Not sure if I’m doing something wrong or if I ran into the bug mentioned here (https://github.com/firebase/firebase-admin-node/issues/1077)