Firestore emulator calls Google APIs to check auth token
See original GitHub issueThis issue is kinda related to #2637 since it deals with the same end result. I figured this bug deserves its own issue though, because it seems so be related to Firestore this time.
Version info
Angular: 10.2.0
Firebase: 8.0.1
AngularFire: 6.1.0-rc.3
How to reproduce these conditions
Failing test unit, Stackblitz demonstrating the problem
https://github.com/jornetsimon/af-auth-debug Updated with commit reproducing the issue.
Steps to set up and reproduce
- Set up the Authentication & Firestore emulators using the new 6.1 injection tokens.
- Set up an authentication method (email/password for example) and implement it on a page
- Subscribe to authState
- Inject AngularFireStore on a separate routed component (lets call it ComponentB)
- Sign up : no issue
- Reload the app, navigate to ComponentB :
- Now load the app directly on the route pointing to ComponentB (e.g. /componentb): a call to Firebase servers (googleapis.com) is made, returning a 400 INVALID_ID_TOKEN error. The user is therefore logged out.
Sample data and security rules
Providers config:`
providers: [
{
provide: USE_FIRESTORE_EMULATOR,
useValue: environment.useEmulators ? ['localhost', 8888] : undefined,
},
{
provide: USE_AUTH_EMULATOR,
useValue: environment.useEmulators ? ['localhost', 9099] : undefined,
},
],
Debug output
When using emulators :
Expected behavior
The AngularFirestore service should target the emulator to verify the auth token.
Actual behavior
There is no problem when authenticating THEN navigating to a component using the AngularFirestore service.
But when loading the app directly through the firestore component endpoint, it seems like it doesn’t have the time to be aware of the emulator config…
Note : The issue is the same with 6.1.0-rc.2 and 6.1.0-rc.3.
Issue Analytics
- State:
- Created 3 years ago
- Comments:17 (7 by maintainers)
@WUKS87 you can try with something like:
The solution provided by @newable works as long as you can make sure that
afAuth.useEmulator(..)
is called before any of the AngularFire modules (Firestore, Database, etc.) is initialized. This solution breaks when you want to use for example Firestore in anAPP_INITIALIZER
factory, or when using NgRx Effects, in which you likely have AngularFirestore injected in the constructor. The problem is that you cannot control in what order theAPP_INITIALIZER
’s dependencies are instantiated and also it doesn’t really matter, because at the point in time when yourAPP_INITIALIZER
withafAuth.useEmulator(..)
is running, the other AngularFire module (be it Firestore that you want to inject in a differentAPP_INITIALIZER
) has already been created before you manage to callafAuth.useEmulator(..)
. NgRx Effects on other hand are being instantiated even before theAPP_INITIALIZER
s are done, so in case of NgRx Effects, you are out of luck even with anAPP_INITIALIZER
. I have seen a workaround for NgRx Effects where you provide the effects in an injection token after theAPP_BOOTSTRAP_LISTENER
but again this leads to issues where the effects are registered too late and also providing working feature effects seemed to be an issue.What I resorted to was the following and it takes care of both issues.
main.ts
firebase.auth().useEmulator(..)
after you initialize the Firebase appFIREBASE_OPTIONS
token in theplatformBrowserDynamic
extraProviders
argumentapp
orcore
module (the module where you import AngularFire) import onlyAngularFireModule
without theinitializeApp(..)
callUSE_EMULATOR
injection token forAngularFireAuthModule
The Firebase SDK initialization is not needed when Auth emulator is not being used, so in production builds the
firebase-init-app.ts
can be replaced withfirebase-init-app.prod.ts
that exports an emptyinitialize
function. In that way, you can rely on the dynamic import provided by AngularFire when Auth emulator is not needed.main.ts
firebase-init-app.ts
core.module.ts