Firebase-tools: Add firebase authentication emulator to emulator suite

Created on 26 Sep 2019  ·  66Comments  ·  Source: firebase/firebase-tools

Is it possible to emulate the authentication API for faster local development and end to end testing? With the Firestore emulator, we don't have to create different projects for different environments (dev, testing, staging, prod), we can just use emulator, seed data to it from JSON files in watch mode for development, or seeding for every test case, etc. To be able to write end to end test that has a user log in, navigation based on role, and then some action, we have to create a separate project to isolate test users, and also seed and clear users there for every test case.

emulator-suite feature request

Most helpful comment

We're hard at work on a full auth emulator which will hopefully be what
everyone wants. No timeline I can offer right now but it's a high priority
for us.

On Fri, May 22, 2020 at 8:12 AM ChuckB notifications@github.com wrote:

@samtstern https://github.com/samtstern Any progress or another
solution to this issue/feature? I need (1) setEmulatedUser to work with the
the cloud Firestore emulator so that I can do manual testing locally.

Per your comment: on Oct 17, 2019
_I think clearly (2) is the right story but I was trying to get a sense of
how many people would be happy with (1) since it's substantially simpler to
implement and maintain.

(1) Sign in to use services like Firestore or Realtime Database without
actually creating real users. Right now that's what something like
setEmulatedUser would solve. It would just allow you to have a bogus auth
token locally that the emulators would accept but it would be rejected by
prod. More safety, more isolation, etc._


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/firebase/firebase-tools/issues/1677#issuecomment-632660684,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ACATB2Q4LV7NXMQFEALNPXLRSZT25ANCNFSM4I27PTFA
.

All 66 comments

@vladimirdjurdjevic thanks for raising this! This is on our list of things to do, but we have not yet decided on how much of the auth service to emulate and the best strategy to do it. Certain things (like anonymous auth) are very easy to emulate while others (like SMS authentication) are very hard.

But we definitely want to enable the end-to-end use case you mentioned!

Question: would you find it useful if there was a library that allowed you to locally mock a Firebase user for use with the emulators? Something like:

firebase.auth().setEmulatedUser({
   uid: 'abc123',
   // ...
});

@samtstern Would the call to setEmulatedUser() also trigger any functions.auth.user().onCreate() emulated cloud functions? If so, that would be very useful.

@samtstern That would help some testing scenarios for sure, but still require real instance for development. My idea is to avoid creating multiple firebase projects for different environments, and to be able to develop locally (offline perhaps). Another approach would be to support different environments for services. If we could create different environments for let's say firestore and auth under the same project, it would solve many issues. I know I can create project per environment, but that's a real pain in the ass. Configuring every environment, replicating data, etc. Ideally, I would like to be able to create one firebase project, and if I need dummy data for manual testing, I could just create a staging environment for firestore, and upload data there.

@noelmansour good question! That wouldn't be too hard to do, we'd probably want two different calls like signInAsEmulatedUser and signUpAsEmulatedUser where only the second triggers the function.

@vladimirdjurdjevic totally agree that a full-featured emulator is best. Could you explain what things you would need from a "real instance for development" that are not solved by being able to set the user locally?

Question: would you find it useful if there was a library that allowed you to locally mock a Firebase user for use with the emulators?

Really useful, it would help a lot.
Right now I'm just setting to true the rule function validating logged user every time I have to test something locally, it's pretty unsafe yet probably the simpler thing I can do without emulated current user.

Yes this would be incredibly useful

I also would like to unit test functions.auth.user().onCreate(). I suppose right now the best workaround is essentially export callback function passed to onCreate and supply fake user object to it.

For that kind of unit testing check out the firebase-functions-test
library, which helps you invoke your function handlers with mock data.

On Sun, Oct 13, 2019, 5:44 AM Daniel K. notifications@github.com wrote:

I also would like to unit test functions.auth.user().onCreate(). I
suppose right now the best workaround is essentially export callback
function passed on onCreate and supply fake user object to it.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/firebase/firebase-tools/issues/1677?email_source=notifications&email_token=ACATB2QYJLX2LNVDTWJV25TQOMJ4VA5CNFSM4I27PTFKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBCVQIQ#issuecomment-541415458,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ACATB2SO3IR6UB73F4EMZPTQOMJ4VANCNFSM4I27PTFA
.

@samtstern That actually works along with Firestore emulator? Base on this I got the impression it's for a different purposes.

image
https://firebase.google.com/docs/functions/unit-testing#initializing

I certainly don't want online mode for unit testing, that would be a slowpoke. And I am not sure if I can access the Firestore emulator by "stubbing".

@FredyC thanks for pointing out those docs. The words used are confusing because the "modes" are not a switch you can enable, they're just describing strategies you can take.

If you were to start up the Firestore emulator alongside your unit tests, your code could definitely connect to it. If you set the FIRESTORE_EMULATOR_HOST environment variable the Firebase Admin SDK will automatically connect to the Firestore emulator (firebase emulators:exec does this for you).

@samtstern I still have trouble connecting dots and how is all that going to help me to test functions.auth.user().onCreate()? I mean it's great that functions will connect to emulator instead of a production version, but that's only Firestore, right? How do I invoke user creation from tests to actually have the function code to kick in?

There seems to be some cryptic method makeUserRecord in the mentioned firebase-functions-test, but it doesn't make much sense how would that work or how to actually use it.

I tried calling auth.createUserWithEmailAndPassword() from the @firebase/testing package, but that's complaining about invalid API key, so I assume it would work with online version only.

When I search through org for that env variable you have mentioned, it's only in three places and none seems to be relevant to auth really. Unless it's hidden by some string concatenation.

I've been also browsing through the https://github.com/firebase/functions-samples but I found no examples of unit testing there.

Can you please make some sense of this? :)

I also have another case, somewhat opposite, where the cloud function code is using admin.auth().getUserByEmail() call. Surprisingly it doesn't end with the error, but I have no idea how I would create that user so it can be returned. Except of course mocking out the whole admin module, but that's crazy :)

@samtstern Sorry for the delay. When I say real instance, I mean real instance :D Ideally, I just want to swap config in my angular environment file for development, and to keep implementing auth features like my app is talking to real API, but it actually emulator running on my machine, and I can do it offline. Now, I understand challenges with sending SMS for example. It would be silly to expect the emulator to send real SMS to my phone, but you could maybe just print it to console (the content of SMS that would be sent). It's probably more hassle than the value with this. That's why I think that just supporting multiple environments per project could make stuff much better. It takes to much time to replicate configs between multiple projects for different environments. And also managing multiple service accounts for scripts to be able to seed data to different Firestore projects is a pain. That's why I taught that if we had a whole firebase platform emulated, we could use that for every non-production environment, and manage just one real firebase project. But maybe just supporting multiple environments per project is a better solution with an acceptable outcome.

@FredyC thanks for all your feedback! It's really helpful to us to see how confusing this can be. There are two main things people want to do in their tests related to auth:

  1. Sign in to use services like Firestore or Realtime Database without actually creating real users. Right now that's what something like setEmulatedUser would solve. It would just allow you to have a bogus auth token locally that the emulators would accept but it would be rejected by prod. More safety, more isolation, etc.
  2. Actually test authentication directly. This would have a few pieces:
    a. An auth emulator that responds to all the necessary API calls so that you can point the Auth SDKs at it.
    b. Integration between that emulator and the functions emulator so that .onCreate functions are triggered correctly.
    c. Auto-mocking inside the functions emulator so that admin.auth() points to the Auth emulator, just like we do for Firestore and RTDB today.

I think clearly (2) is the right story but I was trying to get a sense of how many people would be happy with (1) since it's substantially simpler to implement and maintain.

@samtstern I see. Correct me if I am wrong, but isn't the (1) already solved? I mean in tests I can just call the following and Firestore emulator will recognize me as that user so I can test against security rules. I haven't actually tried that yet, but looks promising so far :)

  const app = firebase.initializeTestApp({
    projectId,
    auth: {
      uid: 'owner'
    }
  })

The (2) definitely sounds very useful, but a lot more complex to tackle for sure. Sadly, my insight into the full product is so limited, I cannot really offer any useful ideas here.

I think it should be built incrementally. Instead of trying to cover all scenarios at once, build it based on known use cases and adding on the go. In my limited opinion emulating "user database" along with function triggers don't seem that hard to do.

@FredyC you're right that (1) is solved for use inside test suites. But the other use case is actually connecting your Android/iOS/Web app directly to the emulator for local development. In which case you can't use @firebase/testing.

I see. Honestly, it would be kinda superb if @firebase/testing could be used cross-platform instead of having separate solutions. I mean how hard it can be to redirect communication to the emulator? Isn't the FIRESTORE_EMULATOR_HOST for exactly that? Although I think something like FIREBASE_EMULATOR_HOST would be more appropriate if the emulator is going to have other services as well.

@vladimirdjurdjevic I am thinking, wouldn't actually work to basically mock out the signInWithPhone method so you can control its behavior? Then you don't need to worry about an emulator and getting simulated SMS code in the console :)

Of course, then you need some way to authenticate toward the emulator for Firestore (and connect to it). Something like I outlined in previous https://github.com/firebase/firebase-tools/issues/1677#issuecomment-542897671. There is an underlying method for generating unsecured tokens: https://github.com/firebase/firebase-js-sdk/blob/master/packages/testing/src/api/index.ts#L64. Not sure if that would work.

Of course, mocking 3rd party libraries is not always that easy, but once figured out, it can bring great results. Eventually, it could be extracted to some library to make it generally easier.

I am also thinking these signIn methods can throw quite a plethora of error codes which is something proper tests should take care of as well. That's easy to do with mocking as well.

@samtstern Extending the firebase.auth() namespace context with something topical like setEmulatedUser seems like an anti-pattern with the existing emulation strategies. Is that recommendation perhaps influenced by ease-of-extensibility on the package side?

Inline with the other emulators, I would expect a separate authentication service tier to be launched over HTTP and a client-side config can redirect the existing API surface to utilize.

I would much rather have eccentric AuthN cases return errors with the Admin and Client API minimally supporting CRUD for basic users over username/password. Heck, i think even starting with Custom Token support in the Admin and signInWithCustomToken would go really far. Maybe implement low hanging fruit with an API support matrix published in the docs.

To @FredyC point, the current strategy for integration Auth testing is to conditionally import the @firebase/testing in application code to route to the custom initializeTestApp call. This action both stresses package exclusion at build-time for project teams, and also spreads the emulator redirect configs across two package APIs (initializeTestApp and firestore.settings/functions.useFunctionsEmulator)

Hack the planet!

the current strategy for integration Auth testing is to conditionally import the @firebase/testing in application code to route to the custom initializeTestApp call.

Um, I am calling that method inside tests. The trick is that regular initializeApp resides in index.ts which imports functions. It's being called when emulator starts, but when tests are executing, it's a different process and it doesn't conflict with each other. So there is really no burden of conditional import.

Of course, this might be different for testing auth in eg. web app where test runner would share the process with app code. However, with unit testing you don't usually import a whole app into a test. The initializeApp is probably done in some code that's not relevant to tests and is not imported at all.

@FredyC Agreed on the documented usages for unit tests. Was really speaking to full-app scenarios where the apis diverge and dynamic imports go off the documented map.

I just wanted to give you attribution for Honestly, it would be kinda superb if @firebase/testing could be used cross-platform instead of having separate solutions. digital high five

@FredyC thanks for all your feedback! It's really helpful to us to see how confusing this can be. There are two main things people want to do in their tests related to auth:

  1. Sign in to use services like Firestore or Realtime Database without actually creating real users. Right now that's what something like setEmulatedUser would solve. It would just allow you to have a bogus auth token locally that the emulators would accept but it would be rejected by prod. More safety, more isolation, etc.
  2. Actually test authentication directly. This would have a few pieces:
    a. An auth emulator that responds to all the necessary API calls so that you can point the Auth SDKs at it.
    b. Integration between that emulator and the functions emulator so that .onCreate functions are triggered correctly.
    c. Auto-mocking inside the functions emulator so that admin.auth() points to the Auth emulator, just like we do for Firestore and RTDB today.

I think clearly (2) is the right story but I was trying to get a sense of how many people would be happy with (1) since it's substantially simpler to implement and maintain.

@samtstern first of all I would ❤️to have this kind of emulation.

I would see no. 1 very useful for writing e2e tests. Currently I have to use real instance for authentication while I can use emulator for hosting, rules, firestore and functions.

I think it should be possible to use setEmulatedUser to mock user in same way it's done in firebase.initializeTestApp. It's should be possible to submit e.g. custom tokens and other user related data.

It should also be possible to get sample credentials which could be used in client app with firebase.auth().signInWithCredential(credential)

Thank you @vladimirdjurdjevic for bringing up this issue! We were looking for a solution for almost a year already.

We would like to see a real emulator for three things:

  1. e2e tests for the whole app, so we do not have to create different environments as @vladimirdjurdjevic said.
  2. Integration tests for the backend, where the APIs are called and the user should be validated at Firebase.
  3. All of our developers are using a central Firebase environment during development, which causes lots of collisions. Of course, every developer could create their own Firebase project but they still need to manage their test users in the Firebase dashboard which is not ideal. Also, we would like to develop our app offline that is not possible today because of the lack of a real emulator.

I hope that you will release something for us soon, it would make your product more valuable! Developer productivity is very important in such services!

This seems to be a feature on many people's wish list. Firebase auth seems to be the #1 IDaaS right now pricing wise, so it's really a pain that you can't develop locally with it with Cloud Functions. Hope the FB team has updates for us soon! 🙏

Edit: Pinging @mbleigh from @firebase-ops since this thread is buried under issues...

I also have this error ... function ignored because the auth emulator does not exist or is not running.

this is triggered by this code:

functions.auth.user().onDelete()

any info on this ...

@dominikfoldi

I agree with your points. One tip that might help you meanwhile:

Of course, every developer could create their own Firebase project but they still need to manage their test users in the Firebase dashboard which is not ideal.

You can seed and manage users programmatically using firebase admin SDK, e.g. auth().createUser, see also https://firebase.google.com/docs/auth/admin/manage-users

After reading this thread I think people here might find Foundry useful.

I'm one of the co-founders of Foundry. Foundry is a CLI tool takes your Firebase Cloud Functions and creates a copy of your production Firebase app on our servers that act as your development environment in which you directly run your code. No configuration is required.

Foundry watches your source code files and every time you save your code locally we run it on our servers and give you back the results within just a few seconds. Everything is super fast.
You specify what Firestore, RealtimeDB, and Auth Users data should be copied from your production app through our YAML file so you have them available during the development.

 users:
      - getFromProd: 5 # Copy first 5 users from your Firebase project
      - getFromProd: ['id-1', 'id-2'] # Copy users with the specified IDs from your Firebase project

 # Copy first 3 documents from production from the collection 'userWorkspaces'
 # also add a custom document with id 'new-user-workspace' with a new data
 # format that you want to use
 firestore:
     - collection: userWorkspaces
       docs:
         - getFromProd: 3
         - id: new-user-workspace
           data: {"newDataFormat": 42}

You also specify how we should trigger your cloud functions when we run your code. It works sort of like a REPL for your cloud functions. That way you are always sure that your cloud functions will work correctly with production data and in the production environment once you deploy them.
Also, your cloud functions act as if they were deployed. That means that they get triggered if you add/delete users, edit your Firestore, or edit your RealtimeDB.

These dev environments are created ad-hoc once you start your session. So everyone in your team operates in their own environment where they can mess around.

I don't want to spam the discussion here so feel free to email me any questions [email protected]
I'm more than happy to help you set up Foundry in your projects just send me an email!

Yet, from how you described it and what I read on the homepage, that service is cloud-based.
Firebase emulator instead works even offline, hence its usefullness for automatic testing.

@samtstern Any progress or another solution to this issue/feature? I need (1) setEmulatedUser to work with the the cloud Firestore emulator so that I can do manual testing locally. Another option would be to have a command line argument that sets the user id when the emulator is started. In this way the emulator would run under the user id passed in during start-up. In this way the rules could be tested locally.

Per your comment: on Oct 17, 2019
_I think clearly (2) is the right story but I was trying to get a sense of how many people would be happy with (1) since it's substantially simpler to implement and maintain.

(1) Sign in to use services like Firestore or Realtime Database without actually creating real users. Right now that's what something like setEmulatedUser would solve. It would just allow you to have a bogus auth token locally that the emulators would accept but it would be rejected by prod. More safety, more isolation, etc._

We're hard at work on a full auth emulator which will hopefully be what
everyone wants. No timeline I can offer right now but it's a high priority
for us.

On Fri, May 22, 2020 at 8:12 AM ChuckB notifications@github.com wrote:

@samtstern https://github.com/samtstern Any progress or another
solution to this issue/feature? I need (1) setEmulatedUser to work with the
the cloud Firestore emulator so that I can do manual testing locally.

Per your comment: on Oct 17, 2019
_I think clearly (2) is the right story but I was trying to get a sense of
how many people would be happy with (1) since it's substantially simpler to
implement and maintain.

(1) Sign in to use services like Firestore or Realtime Database without
actually creating real users. Right now that's what something like
setEmulatedUser would solve. It would just allow you to have a bogus auth
token locally that the emulators would accept but it would be rejected by
prod. More safety, more isolation, etc._


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/firebase/firebase-tools/issues/1677#issuecomment-632660684,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ACATB2Q4LV7NXMQFEALNPXLRSZT25ANCNFSM4I27PTFA
.

1. Sign in to use services like Firestore or Realtime Database without actually creating real users. Right now that's what something like setEmulatedUser would solve. It would just allow you to have a bogus auth token locally that the emulators would accept but it would be rejected by prod. More safety, more isolation, etc.

I would be happy with Number 1 here, in the interim

@rishisingh-dev it's not possible to get an auth emulator running because the firebase emulators currently do not ship one.

But it is perfectly possible to test cloud functions that involve auth in them. You can refactor the function that needs some auth API and mock it on the tests, while providing the real one on the firebase functions file. The fidelity of your test setup is lower, but then it becomes a matter of degree, not a matter of kind: you're just testing the auth calls directly but you can test what you expect them to be.

In that SO question it would be something like:

function sendWelcomeEmail(user) {
  console.log(user.uid);
  console.log(user.email);
  console.log(user.displayName);
}

exports.sendWelcomeEmail = functions.auth.user().onCreate((user) => sendWelcomeEmail(user));

And on your tests you call sendWelcomeEmail directly to ensure it does what you need it to do.

Imagine you have a more complicated cloud function called addFriend, where the user inputs a friends email and you want the uid. You can get that via auths getUserByEmail.

function addFriend(email, getUserByEmail ) {
  const friendUid = getUserByEmail(email);
  // do things with friendUid;
}

exports.addFriend = functions.https.onCall(async (data, context) => {
  const email = data.email;
  const getUserByEmail = (email) => admin.auth().getUserByEmail(email);
  return { res: await addFriend(email, getUserByEmail ) };
}

On the cloud fn declaration you send in the real getUserByEmail, but on your tests you instead send in a fake one:

async function testAddFriend() {
  const emails = {"[email protected]": "test-uid")
  const fakeGetUserByEmail = (email) => emails[email];
  addFriend("[email protected]);
  // verify the things were done with friendUid
}

I don't feel this is significantly different than testing any third party API in a unit test. Having the firebase emulators provide auth removes boilerplate to end-to-end testing scenarios, but it doesn't significantly alter the unit tests since you wouldn't want persistent state to be kept between tests anyway.

I'd love to be able to run this locally without having to upload to the cloud to check

export const onCreate = functions.auth.user().onCreate((user) => {
    addGravatarURLtoUserData(user.uid, user.email)
})

export const addGravatarURLtoUserData = async (uid, email) => {
    const hash = crypto.createHash("md5").update(email).digest("hex")
    await admin.database().ref(`users/${uid}`).update({ gravatarURL: uid })
}

By the way, can I get user.displayName inside onCreate function?

yes if it is set I think, did you try it?

Yes, it returns null.
I tried it on cloud (not locally).

Screen Shot 2020-07-10 at 2 43 12 AM

My code is here.

exports.sendWelcomeEmail = functions.auth.user().onCreate((user) => {
  console.log(user.uid);
  console.log(user.email);
  console.log(user.displayName);
});

Interesting well I don’t use display name , I use custom users displayName for
real-time db

/**
 * updates Custom data in the realtime datastore users object, except for the username
 * @param data
 * @returns {Promise<void>}
 */
export async function updatePersonalData(data) {
    const { displayName } = data
    try {
        await firebase
            .database()
            .ref("users/" + firebase.auth().currentUser.uid)
            .update({
                displayName: displayName,
            })

        userDataStore.update((user) => {
            return { ...user, displayName: displayName }
        })
    } catch (e) {
        alert(e.message)
    }
}

On Fri, 10 Jul 2020 at 10:44, rishisingh-dev notifications@github.com
wrote:

Yes, it returns null.
I tried it on cloud (not locally).

[image: Screen Shot 2020-07-10 at 2 43 12 AM]
https://user-images.githubusercontent.com/56976320/87140958-29f3ac80-c257-11ea-98d3-084fad619de7.png

My code is here.

console.log(user.uid);
console.log(user.email);
console.log(user.displayName);
});```


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/firebase/firebase-tools/issues/1677#issuecomment-656587759,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AABU35Q27EMMHYAYU5CNZR3R23PIDANCNFSM4I27PTFA
.

>

Kind regards

Nikos Katsikanis

Yes, my primary goal was updating the database with user information inside onCreate function.
But since I can't get displayName, I made a onCallable function, and did it.

Thanks.

@samtstern I am very happy to see you working on this :) Just started new project with firebase, and dev experience is already much better (with emulator ui and --inspect-functions option). Looking forward to see auth emulator in action :) Great job!

another of the best thing is that I don't have to open chrome with no security

@samtstern

Two month later, is it now possible to give a rough estimate?

We would like to ship beginning of the next year. We are now faced with the decision if we start to write integration tests against a real project or if we wait a few month for the auth emulator. Could you help us a bit here?

Best,

Niklas

Our policy at Firebase is not to give estimates on when something will launch unless we're 100% sure. Right now we're working hard on the Auth emulator but we're not close enough to being done to pick a launch date.

It's one of our top priorities, but I think you should not wait for us to start testing your app. Write your tests against prod today, switch them to target the emulator when it's available.

Alright, thanks @samtstern. That helps!

Something we'd really like to use an auth emulator for is testing Cloud Functions and Firestore requests that involve Custom Claims on user tokens. We can sort of test custom claims with Firestore in the rules playground in the Firebase Console, but a full-fledged auth emulator would theoretically enable us to do much more in the way of testing when it comes to user tokens.

To be clear: we're committed to a full-fledged auth emulator that emulates the actual service endpoints (wherever possible). We're no longer considering something lightweight like my earlier comments suggested.

@samtstern that's great to hear (along with the custom claims, since that's often used with third party integrations). Is there anywhere we can keep up with the progress/ETA?

@fandy no sorry we don't have anything to share yet...

Thanks Sam, currently I’m doing all my testing manually because it’s not
worth the effort to write e2e tests without Auth mocks

On Wed, 26 Aug 2020 at 14:32, Sam Stern notifications@github.com wrote:

>
>

@fandy https://github.com/fandy no sorry we don't have anything to
share yet...


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/firebase/firebase-tools/issues/1677#issuecomment-680850282,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AABU35UAQDBYEXKKINJSM43SCT6E7ANCNFSM4I27PTFA
.

--

Kind regards

Nikos Katsikanis

To work around this, I experimented with importing @firebase/testing in the browser. That didn't really work. This, however, does: mangle @firebase/testing source to copy out the following slightly edited chunk:

import firebase from "firebase/app"
import * as component from "@firebase/component"
import * as util from "@firebase/util"
import { __awaiter, __generator } from "tslib"

function createUnsecuredJwt(auth) {
    // Unsecured JWTs use "none" as the algorithm.
    var header = {
        alg: 'none',
        kid: 'fakekid'
    };
    // Ensure that the auth payload has a value for 'iat'.
    auth.iat = auth.iat || 0;
    // Use `uid` field as a backup when `sub` is missing.
    auth.sub = auth.sub || auth.uid;
    if (!auth.sub) {
        throw new Error("auth must be an object with a 'sub' or 'uid' field");
    }
    // Unsecured JWTs use the empty string as a signature.
    var signature = '';
    return [
        util.base64.encodeString(JSON.stringify(header), /*webSafe=*/ false),
        util.base64.encodeString(JSON.stringify(auth), /*webSafe=*/ false),
        signature
    ].join('.');
}

function initializeApp(accessToken, options) {
    var _this = this;
    var app = firebase.initializeApp(options);
    if (accessToken) {
        var mockAuthComponent = new component.Component('auth-internal', function () {
            return ({
                getToken: function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
                    return [2 /*return*/, ({ accessToken: accessToken })];
                }); }); },
                getUid: function () { return null; },
                addAuthTokenListener: function (listener) {
                    // Call listener once immediately with predefined accessToken.
                    listener(accessToken);
                },
                removeAuthTokenListener: function () { }
            });
        }, "PRIVATE" /* PRIVATE */);
        app._addOrOverwriteComponent(mockAuthComponent);
    }
    return app;
}

export function initializeTestApp(options) {
  let accessToken = undefined
  if (options.auth !== undefined) {
    accessToken = createUnsecuredJwt(options.auth)
  }
  return initializeApp(accessToken, options)
}

Now in your app browser-side code, you can import that, and

  let app
  if (dev) {
    app = initializeTestApp({projectId: "test", auth: {uid: "testuser"}})
    app.firestore().settings({
      host: "localhost:8080",
      ssl: false,
    })
  } else {
    app = firebaseProduction.initializeApp({ firebase config here })
    app.firestore().settings({ firestore config here })
  }
  window.firebase = app

That works great! Now when I'm running in development, I have a local fake user that the emulator thinks is "testuser" (like the firestore security rules testing guide shows).

Another workaround that I use is to stub your authentication (I'm using generated fake users for tests).

TypeScript example:

import type { User as AuthUser } from '@firebase/auth-types'
// not importing a type, but a module of types
import { auth as authTypes} from 'firebase/app'
type Auth = authTypes.Auth

export const authStub = {
    getUser(uid: string) {
        // for uids like `testuser1234uid`
        let n = uid ? uid.replace("testuser", '').replace("uid", '') : ''
        return Promise.resolve({
            uid,
            email: `test.user${n}@foo.com`,
            emailVerified: true,
            providerData: [{
                providerId: 'google.com',
                email: `test.user${n}@foo.com`,
                uid: `testuser${n}provideruid`,
                phoneNumber: null,
                displayName: `Test User ${n}`.trim(),
                photoURL: 'https://thispersondoesnotexist.com/image',
            }],
            metadata: {
                // https://firebase.google.com/docs/reference/admin/node/admin.auth.UserMetadata
                createTime: new Date().toUTCString(),
                lastSignInTime: new Date().toUTCString()
            },
            customClaims: {
                username: `testuser${n}`
            }
        })
    },
    deleteUser(uid: string) {
        return Promise.resolve()
    },
    async updateUser(uid: string, data: AuthUser) {
        let user = await this.getUser(uid)
        return { ...user, data }
    },
    setCustomUserClaims(uid: string, customUserClaims: Object): Promise<void> {
        return Promise.resolve()
    }
}

export const auth = <Auth><unknown>authStub

Also modify your rules as auth.token is not emulated. For instance:

const rules = fs.readFileSync(__dirname + '/src/firebase/firestore/firestore.rules', 'utf8')
const modifiedRules =
    rules
        .replace(/request\.auth\.token\.email_verified/g, "true")
        .replace(/request\.auth\.token\.firebase\.sign_in_provider/g, "'password'")

await firebase.loadFirestoreRules({ projectId, rules: modifiedRules })

It's working great for me. Hope it helps…

If you're following this thread and willing to be an Alpha tester of the Firebase Authentication Emulator, follow these steps:

  1. Sign up for the Firebase Alpha program: https://services.google.com/fb/forms/firebasealphaprogram/
  2. Send me an email at [email protected], make sure to send it from the email address you will use for testing.

Please only do this if you're seriously interested in trying out an early-stage emulator and providing feedback! There will be bugs and some parts of the setup will be hard, but we want to know what you think.

@samtstern This is great news! I would love to try it, but I am going to production with my current project by the end of the week, so I can't afford to play with it at the moment. Will sign up for alpha as soon as I can :) Thanks for the great work.

100% will want to try this! your the man Sam!

@samtstern looking forward to trying it and help whatever I can!

I need use feature of auth to test functions locally from Android, the context of Auth is always null

Good news, the Authentication Emulator is part of the fresh 8.14.0 release! 🙌🎊

Thank you for the hard work guys and @samtstern 💪

awesome guys!

I'm just the messenger! The Auth emulator was 99% built by @yuchenshi ... and that's why I'm going to let him have the honor of closing this issue when he wakes up.

Is there any documentation on this new emulator? (how to install, configure clients, etc)

P.S.Thanks a lot for all the hard work on this. This is going enable all sorts of cool stuff for us.

@nicoburns very soon! Official announcement, docs, and all that good stuff coming very shortly.

Great news! :) Can't wait to give it a try :)

I know you've been waiting for this, so let's just cut to the point:

  • Firebase Authentication Emulator is now available. You can get it by installing Firebase CLI >= v8.14.0.
  • Follow the Emulator Suite guide to get started, and connect your apps.
  • For exciting announcements like this and much much more, tune in to Firebase Summit livestream RIGHT NOW.**

**Shameless plug: I'm also doing a session on "How to set up CI using the Firebase Emulator suite" later today. Locating that on the session schedule is left as an exercise for the reader.


_P.S. I really cannot take 99% of the credit since the Auth Emulator is of course teamwork. Various people at Firebase and Firebase developers (you) played a big part in this too. Thank you!_

@yuchenshi Is it possible to export created users on exit, just like with firestore emulator?

@vdjurdjevic not yet, we're working on that.

This is a really popular issue and every update notifies 50-100 people. Since we have now released the Auth emulator I am going to lock this issue from future updates. If you have a question, bug, or feature request please start a new issue!

Was this page helpful?
0 / 5 - 0 ratings