firebase-tools: Functions shell/emulator unable to load default credentials
[REQUIRED] Environment info
firebase-tools: 7.12.1
Platform: Debian on WSL on Windows 10
[REQUIRED] Test case
import * as functions from 'firebase-functions';
const admin = require('firebase-admin').initializeApp(functions.config().firebase);
exports.action1 = functions.https.onCall(() => {
return admin.database().ref('action').push({ 'a': 1 })
});
[REQUIRED] Steps to reproduce
npm run shell
with the above code, execute function action({})
[REQUIRED] Expected behavior
The shell environment should be able to locally simulate the function and access the database, according to the documentation: Cloud Firestore and Realtime Database triggers already have sufficient credentials, and do not require additional setup.
[REQUIRED] Actual behavior
I receive the following message:
@firebase/database: FIREBASE WARNING: {“code”:“app/invalid-credential”,“message”:“Credential implementation provided to initializeApp() via the "credential" property failed to fetch a valid Google OAuth2 access token with the following error: "Error fetching access token: Error while making request: getaddrinfo ENOTFOUND metadata.google.internal. Error code: ENOTFOUND".”}
Some digging through the documentation provided me with various different answers, none of which solved my issue. Please note that I would like to locally develop with the same code as the one that I deploy. Some things I found:
-
I tried with and without
functions.config().firebase
but it’s not clear when and if this is required -
Setup Admin Credentials using the export command. I changed the default command to:
"shell": "export GOOGLE_APPLICATION_CREDENTIALS=\"my-owner-key.json\" && tsc --watch --preserveWatchOutput & firebase functions:shell",
According to the (closed) issue #595 for some reason a protect_env
flag sets this environment variable to an empty string. I don’t see the reasoning for this ‘protection’ as the documentation explicitly explains you need to set this variable if you wish to use the shell in an authenticated fashion. PR #1252 added the functionality to disable protect_env
but I couldn’t get the --disable-features
flag working or even find any documentation on it anywhere.
serviceAccount = require('./serviceAccount.json');
const adminConfig = JSON.parse(process.env.FIREBASE_CONFIG);
adminConfig.credential = admin.credential.cert(serviceAccount);
admin.initializeApp(adminConfig);
Somehow injecting the json is supposed to work according to the documentation however this code fails to compile with the following error:
error TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
Type 'undefined' is not assignable to type 'string'.
const adminConfig = JSON.parse(process.env.FIREBASE_CONFIG);
It also feels hacky and would not be transferrable to the server as-is as it explicitly depends on a .json
credential file being deployed.
Edit: I found a 4 month old issue on this topic that is still regularly receiving reports of users encountering the same problem: #1708
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 5
- Comments: 20 (9 by maintainers)
To everyone watching this thread: today we released version
8.5.0
of the CLI which contains big changes for how authentication works in the Functions Emulator.Namely: if you’re logged into the CLI with
firebase login
we will pass those credentials into the emulator as temporaryGOOGLE_APPLICATION_CREDENTIALS
(unless you’re providing your own). This should mean you don’t need to rely ongcloud
for basic authentication anymore.If this causes any problems please file a new issue!
Hmm ok so after some more digging I found out:
functions:shell
but actually anything that uses the emulator (includingemulators:start
)gcloud auth application-default login
but I don’t see why that was necessary …@quantuminformation try using
$HOME
instead of~
. If that doesn’t work then open a new issue, yeah,Got same problem, solved by installing gcloud sdk then running
gcloud auth application-default login
I think firebase cli login should be enough to allow local testing using serve & shell.
Leaving a note for myself so I can pick this back up. Basically right now all of the emulator default credentials happen “by luck”. Most people have a default credential on their machine or they have
GOOGLE_APPLICATION_CREDENTIALS
set.What we need to do is get
firebase login
to create a credential that we can pass down into the emulators which they can use instead of having to rely on one of the implicit methods. This will require a change inauth/credential.ts
infirebase-admin-node
to look in a new location before falling back togcloud
credentials.@nascode @filipesilva thanks for your inputs. This is one of the things I really want to fix in the emulators but as you can see here it’s very hard to get right and I don’t want to make any breaking changes. But I want to let you know I am thinking about it.
@samtstern for me the emulator randomly stopped working, so I actually had to install gcloud and login as a workaround.
firebase-debug.log
firebase emulators:start
The error is caused by accessing
const db = admin.app().firestore(); db.doc(...).get()
UPDATE
Actually the “fix” removed the error message but now the emulated function modifies the data in the online firestore database.
I call the functions like this:
@Karasuni thanks for your very detailed report. I was able to reproduce the behavior as you described it and I agree this is not what we want to happen.