GOOGLE_APPLICATION_CREDENTIALS for dummy Firebase project - firebase

I'm learning to set up Firebase Emulators correctly to work on my projects and I came up with a problem. I can setup the emulators and make them work locally, however, when trying to access firestore it seems to try to access the real Firestore Instance instead of the emulator.
Right now I'm initializing the app like this (in Cloud Functions)
admin.initializeApp();
const db = admin.firestore();
But when I'm running a function I'm getting:
Failed to initialize and load triggers. This shouldn't happen: Failed to read credentials from file GOOGLE_APPLICATION_CREDENTIALS.json: Error: ENOENT: no such file or directory, open 'GOOGLE_APPLICATION_CREDENTIALS.json'
The thing is that if I use the credentials I generated for my project it will work with the real Firestore instance instead of the emulator.
How should I make credentials for my emulated services?

If you are using Firebase Functions emulator as well then Admin SDK will connect to all the running emulators e.g. if only Auth emulator is running then it'll use the emulator and connect to production for other services like Firestore. You can explicitly set the FIRESTORE_EMULATOR_HOST environment variable and Admin SDKs will use the emulator then.
Checkout the documentation for more information.

Related

Firebase functions emulator requesting external network resource: computeMetadata

I have the firebase emulator running in a docker container locally for testing. The emulator includes everything I'm using for my app (firestore, auth, functions, storage) so that I can develop and test independently of the production environment.
However, I'm getting these warnings which are making me nervous:
functions: Beginning execution of "myFunction"
⚠ External network resource requested!
- URL: "http://---.---.---.---/computeMetadata/v1/instance"
- Be careful, this may be a production service.
I don't know what that URL is? Does it mean I've misconfigured something somewhere?
I'm also getting these warnings:
⚠ emulators: You are not currently authenticated so some features may not work correctly. Please run firebase login to authenticate the CLI.
⚠ functions: You are not signed in to the Firebase CLI. If you have authorized this machine using gcloud application-default credentials those may be discovered and used to access production services.
⚠ functions: Unable to fetch project Admin SDK configuration, Admin SDK behavior in Cloud Functions emulator may be incorrect.
But I don't think I want to authenticate, right? I don't want to touch anything to do with the live project on production while testing locally. Can I safely ignore these, or is there a good reason to authenticate?
The warnings are indicative that there had some issues while initialization during the setup for emulators .
Make sure that the emulator is installed by the following command: firebase setup:emulators:firestore, for this you can refer Documentation.
Deploy your function in the firebase in order to get recognized. you can refer to the Documentation using firebase deploy --only functions
Also to be sure please check your Firebase json and see if the local host is configured and not the production host,just to be sure.
For further reference you can follow up the stackoverflow thread Docker authentication issueand Firestore emulatorwhere a similar issue has been raised by other users which might be helpful.

Firebase CLI is not recognizing my project

Why can't anything be easy? I am trying to add push notifications from Firebase Cloud Messaging. When I run firebase init I get the following:
How do I get this to work? I have tried all the solutions I have read here but none of them have worked.
The CLI is recognizing your project, but the initialization is failing due to an error with Cloud Storage for Firebase.
Try going to the Storage section within your Firebase Console (here) and initialize Cloud Storage for Firebase first.
After you've chosen a location for your bucket try running your command again.

Run firebase functions emulator on database without database emulator (towards production cloud instead)

I am having trouble running the firebase functions emulator towards a production database. I have a project which is not publicly released yet so I can run towards production with any negative effects.
My project uses only the realtime database, it does not use Firestore (so other questions on SO are not relevant) The documentation states "Cloud Firestore and Realtime Database triggers already have sufficient credentials, and do not require additional setup." so according to that, I shouldn't need any additional setup in order to point to the production database.
According to all of the documentation on Firebase, the project should run towards the real firebase database if I only start the functions emulator and do not start the database emulator. This warning seems to say so, too:
functions: The following emulators are not running, calls to these services from the Functions emulator will affect production: auth, firestore, database, hosting, pubsub
However, this is not what happens. Instead, I get the following error:
functions[onGlobalClientRequest]: function ignored because the database emulator does not exist or is not running.
I have read the firebase documentation and nothing is really mentioned other than setting credentials should not be needed (but I am setting credentials anyway using export GOOGLE_APPLICATION_CREDENTIALS="/path/to/credentials.json" before running the functions emulator.)
onGlobalClientRequest looks like this:
export const onGlobalClientRequest = functions.database
.ref( client_requests_key + "/{pushedid}")
.onCreate(
async (
snap: functions.database.DataSnapshot,
context: functions.EventContext,
) => {
///.... code here...
},
);
The locally emulated Firebase Functions will be able to write to the Prod database, but will not be able to get triggered by the production database.
Here is a SO answer from a Google employee that states the aforementioned.
Also, quoting from this other SO answer from another Google employee:
In general the rule with emulators:start is that we comprehensively emulate whatever is running. So for example if you're running the Functions and Database emulator, all writes from functions (through admin.database().... will be redirected to the Database emulator. But writes to Firestore (admin.firestore()...) will try and hit production because that emulator is not running.
Operations on a Realtime Database (RTDB) trigger the functions in the corresponding project. So the production RTDB triggers functions of your production project, and the emulated RTDB triggers emulated functions.
If you want to test functions triggered by RTDB operations locally with the emulator, you have to use the RTDB emulator as well. This is explained in the doc here.
If you only want to test HTTP callable functions, then you can use a remote RTDB.

How to run firebase emulators for local development with functions, triggers on remote db?

I'm building a firebase API with cloud functions and want to reach my production Database for local testing.
My problem :
When I launch my two firebase emulator (functions and firestore) with
firebase emulators:start
1- My custom API endpoints run on http://localhost:5001 (this works)
2- My triggers reaches a local dababase on http://localhost:8080 whereas I didn't set FIRESTORE_EMULATOR_HOST=localhost:8080 (I want to reach my production database)
OR
When I launch only my "functions emulator" with
firebase emulators:start --only function
...but my triggers are not reached, probably because of this warning
i functions[userOnCreate]: function ignored because the firestore emulator does not exist or is not running.
On the other side I'm building a reactjs App also with firebase running on localhost:3000
I call my local API from this app with firebase SDK. To reach my emulator, I add the line :
firebase.functions.useFunctionsEmulator('http://localhost:5001');
The local emulators don't work with actual cloud-hosted instances of databases. Everything must be local.
You are always free to file a feature request.
you have to use firebase serve instead for firebase emulators:start

How can I "admin.initializeApp();" no arguments in local

I am always grateful for your help.
I want to write code admin.initializeApp(); both locally and in production.
When I deploy functions to production with no auguments, it works.
But locally, it requires me to write it like below:
const serviceAccount = require("/home/yhirochick/development/ServiceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://xxxx.firebaseio.com/"
});
In the official documentation it says that configuration is applied automatically when you initialize the Firebase Admin SDK with no arguments
But when I execute the command firebase serve --only functions locally and some calls some requests by postman produce the error below:
[2019-07-22T06:45:26.227Z] #firebase/database: FIREBASE WARNING: Provided
authentication credentials for the app named "[DEFAULT]" are invalid. This
usually indicates your app was not initialized correctly. Make sure the
"credential" property provided to initializeApp() is authorized to access the
specified "databaseURL" and is from the correct project.
I want to know How can I "admin.initializeApp();" no arguments locally.
I have grappled with this also and I don't think the local testing scenario currently is explained very well in the official documentation. But here is a solution:
For your local environment you need to download the firebase projects firebase service account json file (found in firebase console under project settings -> service account) and set an environment variable GOOGLE_APPLICATION_CREDENTIALS to point to the file:
# Linux/MACOS version
export GOOGLE_APPLICATION_CREDENTIALS="[PATH_TO_YOUR_SERVICE_ACCOUNT_FILE]"
Read more here, also on how to do this on Windows
Now you will be able to use admin.initializeApp() (with no arguments) locally.
A possible downside of this approach is that you have to set the environment variable each time you fire up a terminal before you start the firebase emulator, because the variable gets deleted when you end the session.
Automate it...
You could automate the export ... command by bundling it together with the command that fires up the emulator. You could do this by adding an entry to the scripts section of your package.json, e.g.:
"local": "export GOOGLE_APPLICATION_CREDENTIALS='[PATH_TO_YOUR_SERVICE_ACCOUNT_FILE]' && firebase emulators:start --only functions"
Then, in this example, you would only need to type npm run local.
Alternative: provide explicit credentials in local environment only
Look at this example: https://stackoverflow.com/a/47517466/1269280.
It basically use a runtime node environment variable to separate between local and production and then use the explicit way of providing credentials in the local environment only.
This is my preferred way of doing things, as I think it is more portable. It allows me to put the service account file inside my codebase and not deal with its absolute file path.
If you do something like this then remember to to exclude the service account file from your repo! (it contains sensitive info).
Background: difference between production and local service account discovery
The reason that admin.initializeApp() (with no arguments) works out-of-the-box in production is that when you deploy to production, i.e. Firebase Functions, the code ends up in a 'Google managed environment'. In Google managed environments like Cloud Functions, Cloud Run, App Engine.. etc, the admin SDK has access to your applications default service account (the one you downloaded above) and will use that when no credentials are specified.
This is part of Google Clouds Application Default Credentials (ADC) strategy which also applies to firebase functions.
Now, your local environment is not a 'google managed environment' so it doesn't have access to the default service account credentials. To google cloud, your local box is just an external server trying to access your private Firebase ressources. So you need to provide your service account credentials in one of the ways described above.
Before I knew this, I thought that because I was already logged in to firebase via my terminal i.e. firebase login and were able to deploy code to firebase, the firebase emulator would also have the necessary credentials for the firebase admin sdk, but this is not the case.

Resources