firebase-tools: Callable function in emulator returns 'unauthenticated' when passing in mock auth via firebase/testing lib
Not sure if this is the right place for this report, or if perhaps I am using the emulators/sdk incorrectly. I would like to write some integration tests and run against the Firebase emulator suite. I found the docs on testing security rules helpful, and it seems like the intention of the @firebase/testing library is to allow testing of functions/database beyond just security rules.
That doc outlines how to mock authentication by passing and auth dictionary to initializeTestApp(..), but when I use the resulting app to call an httpsCallable function, the emulator returns an ‘unauthenticated’ error.
[REQUIRED] Environment info
firebase-tools: 7.0.2 Platform: macOS 10.14.5
[REQUIRED] Test case
Here is a minimal reproduction: https://github.com/ryanmeisters/firebase-callable-emulator-test
It contains a single helloCallable function that returns {hello: "world"}, and a single test that calls the function and verifies the response. The test passes when no auth is passed into initializeTestApp, but gets ‘unauthenticated’ error if auth is passed.
[REQUIRED] Steps to reproduce
- Clone the above repo and
npm install - in the root run
./emulate.sh(compiles typescript and runs emulators) cd functions && npm run test # test fails with 'unauthenticated'- comment out this line and
npm run testagain. Test passes
[REQUIRED] Expected behavior
The callable function should be called and receive the mock auth dictionary
[REQUIRED] Actual behavior
Function returns and unauthenticated error.
Output of firebase emulators:start --debug and function call
➜ FirebaseTestingCallable git:(master) ./emulate.sh
> functions@ build /Users/ryan/Projects/FirebaseTestingCallable/functions
> tsc
[2019-07-06T17:00:46.379Z] ----------------------------------------------------------------------
[2019-07-06T17:00:46.382Z] Command: /Users/ryan/.nvm/versions/node/v8.15.1/bin/node /Users/ryan/.nvm/versions/node/v8.15.1/bin/firebase emulators:start --debug
[2019-07-06T17:00:46.382Z] CLI Version: 7.0.2
[2019-07-06T17:00:46.382Z] Platform: darwin
[2019-07-06T17:00:46.382Z] Node Version: v8.15.1
[2019-07-06T17:00:46.383Z] Time: Sat Jul 06 2019 10:00:46 GMT-0700 (PDT)
[2019-07-06T17:00:46.383Z] ----------------------------------------------------------------------
[2019-07-06T17:00:46.392Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
[2019-07-06T17:00:46.392Z] > authorizing via signed-in user
[2019-07-06T17:00:46.394Z] > refreshing access token with scopes: ["email","https://www.googleapis.com/auth/cloud-platform","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","openid"]
[2019-07-06T17:00:46.394Z] >>> HTTP REQUEST POST https://www.googleapis.com/oauth2/v3/token
<request body omitted>
[2019-07-06T17:00:46.686Z] <<< HTTP RESPONSE 200 content-type=application/json; charset=utf-8, vary=X-Origin, Referer, Origin,Accept-Encoding, date=Sat, 06 Jul 2019 17:00:46 GMT, server=scaffolding on HTTPServer2, cache-control=private, x-xss-protection=0, x-frame-options=SAMEORIGIN, x-content-type-options=nosniff, alt-svc=quic=":443"; ma=2592000; v="46,43,39", accept-ranges=none, transfer-encoding=chunked
[2019-07-06T17:00:46.697Z] >>> HTTP REQUEST GET https://cloudresourcemanager.googleapis.com/v1/projects/testproject-dbefa
[2019-07-06T17:00:47.139Z] <<< HTTP RESPONSE 200 content-type=application/json; charset=UTF-8, vary=X-Origin, Referer, Origin,Accept-Encoding, date=Sat, 06 Jul 2019 17:00:47 GMT, server=ESF, cache-control=private, x-xss-protection=0, x-frame-options=SAMEORIGIN, x-content-type-options=nosniff, server-timing=gfet4t7; dur=252, alt-svc=quic=":443"; ma=2592000; v="46,43,39", accept-ranges=none, transfer-encoding=chunked
i Starting emulators: ["functions","firestore"]
✔ functions: Using node@8 from host.
[2019-07-06T17:00:47.157Z] >>> HTTP REQUEST GET https://mobilesdk-pa.googleapis.com/v1/projects/1077985712794:getServerAppConfig
[2019-07-06T17:00:47.450Z] <<< HTTP RESPONSE 200 content-type=application/json; charset=UTF-8, vary=X-Origin, Referer, Origin,Accept-Encoding, date=Sat, 06 Jul 2019 17:00:47 GMT, server=ESF, cache-control=private, x-xss-protection=0, x-frame-options=SAMEORIGIN, x-content-type-options=nosniff, alt-svc=quic=":443"; ma=2592000; v="46,43,39", accept-ranges=none, transfer-encoding=chunked
✔ functions: Emulator started at http://localhost:5001
[2019-07-06T17:00:47.716Z] Starting emulator firestore with args {"host":"localhost","port":8080,"rules":"/Users/ryan/Projects/FirebaseTestingCallable/firestore.rules","functions_emulator":"localhost:5001"}
i firestore: Logging to firestore-debug.log
✔ firestore: Emulator started at http://localhost:8080
[2019-07-06T17:00:48.406Z] API endpoint: http://localhost:8080
[2019-07-06T17:00:48.406Z]
If you are using a library that supports the FIRESTORE_EMULATOR_HOST environment variable, run:
export FIRESTORE_EMULATOR_HOST=localhost:8080
Dev App Server is now running.
i firestore: For testing set FIRESTORE_EMULATOR_HOST=localhost:8080
i functions: Watching "/Users/ryan/Projects/FirebaseTestingCallable/functions" for Cloud Functions...
[2019-07-06T17:00:48.674Z] Functions runtime initialized.
[2019-07-06T17:00:48.675Z] Disabled runtime features: undefined
[2019-07-06T17:00:48.795Z] Found google-gax at /Users/ryan/Projects/FirebaseTestingCallable/functions/node_modules/google-gax/build/src/index.js
[2019-07-06T17:00:48.795Z] Outgoing network have been stubbed.
[2019-07-06T17:00:48.823Z] Checked functions.config()
[2019-07-06T17:00:48.826Z] firebase-admin has been stubbed.
[2019-07-06T17:00:48.827Z] config() parent accessed!
i functions: HTTP trigger initialized at http://localhost:5001/testproject-dbefa/us-central1/helloCallable
[2019-07-06T17:01:11.648Z] File /Users/ryan/Projects/FirebaseTestingCallable/functions/lib/index.tests.js.map changed, reloading triggers
[2019-07-06T17:01:11.648Z] File /Users/ryan/Projects/FirebaseTestingCallable/functions/lib/index.tests.js changed, reloading triggers
[2019-07-06T17:01:11.649Z] File /Users/ryan/Projects/FirebaseTestingCallable/functions/lib/index.js.map changed, reloading triggers
[2019-07-06T17:01:11.649Z] File /Users/ryan/Projects/FirebaseTestingCallable/functions/lib/index.js changed, reloading triggers
[2019-07-06T17:01:12.794Z] Accepted request POST /testproject-dbefa/us-central1/helloCallable --> helloCallable
[2019-07-06T17:01:12.838Z] Functions runtime initialized.
[2019-07-06T17:01:12.839Z] Disabled runtime features: undefined
[2019-07-06T17:01:12.955Z] Found google-gax at /Users/ryan/Projects/FirebaseTestingCallable/functions/node_modules/google-gax/build/src/index.js
[2019-07-06T17:01:12.955Z] Outgoing network have been stubbed.
[2019-07-06T17:01:12.987Z] Checked functions.config()
[2019-07-06T17:01:12.987Z] Functions runtime initialized.
i functions: Beginning execution of "helloCallable"
[2019-07-06T17:01:12.988Z] Disabled runtime features: undefined
[2019-07-06T17:01:12.989Z] firebase-admin has been stubbed.
[2019-07-06T17:01:12.989Z] config() parent accessed!
[2019-07-06T17:01:13.101Z] Found google-gax at /Users/ryan/Projects/FirebaseTestingCallable/functions/node_modules/google-gax/build/src/index.js
[2019-07-06T17:01:13.101Z] Outgoing network have been stubbed.
[2019-07-06T17:01:13.130Z] Checked functions.config()
[2019-07-06T17:01:13.131Z] firebase-admin has been stubbed.
[2019-07-06T17:01:13.132Z] config() parent accessed!
[2019-07-06T17:01:13.133Z] Trigger "helloCallable" has been found, beginning invocation!
[2019-07-06T17:01:13.133Z]
[2019-07-06T17:01:13.133Z] Running helloCallable in mode HTTPS
[2019-07-06T17:01:13.139Z] {"socketPath":"/var/folders/8j/lw39pjg97xbckxh0bk7rtw8r0000gn/T/firebase_emulator_invocation_74956.sock"}
Output of npm run test
➜ functions git:(master) ✗ npm run test
> functions@ test /Users/ryan/Projects/FirebaseTestingCallable/functions
> tsc && ava -v --serial
✖ we are able to call the callable function Rejected promise returned by test
1 test failed
we are able to call the callable function
/Users/ryan/Projects/FirebaseTestingCallable/functions/node_modules/@firebase/functions/src/api/error.ts:66
Rejected promise returned by test. Reason:
Error (HttpsErrorImpl) {
code: 'unauthenticated',
details: undefined,
message: 'Unauthenticated',
}
new HttpsErrorImpl (node_modules/@firebase/functions/src/api/error.ts:66:5)
_errorForResponse (node_modules/@firebase/functions/src/api/error.ts:175:10)
Service.<anonymous> (node_modules/@firebase/functions/src/api/service.ts:226:19)
step (node_modules/tslib/tslib.js:133:27)
Object.next (node_modules/tslib/tslib.js:114:57)
fulfilled (node_modules/tslib/tslib.js:104:62)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! functions@ test: `tsc && ava -v --serial`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the functions@ test script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/ryan/.npm/_logs/2019-07-06T17_01_13_235Z-debug.log
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 3
- Comments: 18 (10 by maintainers)
@ryanmeisters by the way you can check
if (process.env.FUNCTIONS_EMULATOR)to know when your code is running in the emulator and when it’s notVersion
7.16.2has been released.@eowo @seki2020 thank you for pointing this out. It looks like the library
jsonwebtoken.decode()does not like the JWTs returned from@firebase/testingwhereas it does accept real production Firebase JWTs (which is what I used for testing). I will dig into this and get a fix out this morning.Filed this bug with the testing SDK: https://github.com/firebase/firebase-js-sdk/issues/2803
We can work around it in the CLI though, PR coming.
The fix has been released in
7.16.0@luke-studley sorry about that experience and thanks for the bump! You inspired me to dig deeper and I found a solution I am happy with. PR on the way, this will be fixed in the next release.
@seki2020 is right, we have this issue again in version 7.16.1
Hi folks, I need to remind something here. I found that this issue was fixed by v7.16.0 but perhaps fail by v7.16.1.
[REQUIRED] Steps to reproduce
I am using this repo Actually, to replace nothing but
projectIdto your own project. Don’t comment outauth: { uid: "alice", email: "alice@example.com" }ps: All steps are same as what @ryanmeisters did in this issue.
Test Environment
MacOS: 10.15.3
ps: Please close all and reopen new command windows once you have updated versions of firebase-tools.
Firebase-tools: v7.16.1
run
npm run testthe result isDebug Info by Emulator is
Firebase-tools: v7.16.0
run
npm run testDebug Info by Emulator is
I would be also interested in a better solution to this. I wonder why is it a problem to generate a token with the correct signature. I mean how is it possible that we can communicate with the emulated firestore just fine (there is surely some token handling as well), but the token for functions doesn’t work?
@ryanmeisters How do you approach mocking auth in tests? It seems that error is thrown way before the callable function is accessed.
I am surprised that these “basics” are not figured out yet. How are people testing functions?
Ok so the failure happens when the
firebase-functionsSDK tries to verify the token: https://github.com/firebase/firebase-functions/blob/f3af1759f0bba3c13a0fed9e14682aad76580dc7/src/providers/https.ts#L437My token looks something like this:
Because it’s from the test SDK, it has an invalid signature:
So I think this is working as intended right now, but we want to make the Functions SDK accept an invalid signature when it’s running in the emulator … not sure how to do that in the best way.
@samtstern will best be able to look at this and help triage.