Google Firebase Web App - Error involving Cloud Functions and Firestore - node.js

Recently, I tried to follow a few demos online to get started on a Google Firebase Cloud Functions Node.js server-side code for an application. Upon attempting to add a Firebase App (and Firestore with it),
const functions = require('firebase-functions');
const firebase = require('firebase-admin');
require('firebase/firestore');
var serviceAccount = require("<private key>.json");
const initAppFirebase = firebase.initializeApp({
credential: firebase.credential.cert(serviceAccount),
databaseURL: "<URL>"
});
var db = firebase.firestore();
I begin to get this one error that mentions a missing "annotations.proto" file from the google-gax module (which is apparently imported at some point in Firestore).
Error during trigger parsing: Error occurred while parsing your function
triggers.
Error: The include `google\api\annotations.proto` was not found.
at Function.GoogleProtoFilesRoot._findIncludePath
(C:\...\functions\node_modules\google-gax\lib\grpc.js:312:11)
at GoogleProtoFilesRoot.resolvePath
(C:\...\functions\node_modules\google-gax\lib\grpc.js:298:31)
...
at v1beta1 (C:\...\functions\node_modules\#google-
cloud\firestore\src\v1beta1\index.js:30:10)
at new Firestore (C:\...\functions\node_modules\#google-
cloud\firestore\src\index.js:229:18)
I have looked around on the internet, but nobody else seems to have this problem. I just reinstalled the files, but I am still getting this issue. Removing the Firestore and Firebase initializeApp code allows it to work, so I believe it has something to do with that.
Here are my module versions from package.json
"firebase-admin": "^5.12.0",
"firebase-functions": "^1.0.1",
"firestore": "^1.1.6",
Is there a way to fix this problem (botched installation, outdated libraries, missing code/requires etc.)? Thank you very much.
EDIT: Added code and package.json for version info. I dug around in the actual file \node_modules\google-gax\lib\grpc.js and found that it tries to return a valid path leading to the import file annotation.proto by trying to test google\api\annotations.proto at each parent directory.
var current = originPath;
var found = fs.existsSync(path.join(current, includePath));
while (!found && current.length > 0) {
current = current.substring(0, current.lastIndexOf(path.sep));
found = fs.existsSync(path.join(current, includePath));
}
if (!found) {
throw new Error('The include `' + includePath + '` was not found.');
}
return path.join(current, includePath);
There is, unfortunately, no such directory, though perhaps it is looking for the annotations file in google-proto-files\google\api\annotations.proto (but adding that file in manually leads to further errors). There is also a github issue here https://github.com/googleapis/nodejs-firestore/issues/175 mentioning it.

You say that you're trying to build a web app. But the code you are using is for initializing the Firebase Admin SDK in a (server-side) Node.js script.
If you want to use Firestore in your web app, start with the code you see when you click the WEB tab on this page:
<script src="https://www.gstatic.com/firebasejs/4.12.0/firebase.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.12.0/firebase-firestore.js"></script>
And then:
firebase.initializeApp({
apiKey: '### FIREBASE API KEY ###',
authDomain: '### FIREBASE AUTH DOMAIN ###',
projectId: '### CLOUD FIRESTORE PROJECT ID ###'
});
// Initialize Cloud Firestore through Firebase
var db = firebase.firestore();
You can get the values in that initializeApp call by:
Going to the Project overview page
Click ADD ANOTHER APP
Click Add Firebase to your web app

Related

Initialising Algolia in Firebase Cloud functions

I am using the Algolia extension for Firebase. In Algolia I have an index with many docuemnts. Each user of my app should access only the documents they created. In order to implement this filter I need to generate a specific, filtered API key in Algolia for each user. I am trying to do this with a cloud function in Fireabse.
I get an error when I try to initialize Algolia in my local cloud functions index.js file and then deploy the functions.
Combining the docs of Cloud Functions and Algolia, I am doing this:
const functions = require("firebase-functions");
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
// For the default version
const algoliasearch = require('algoliasearch');
// For the default version
// import algoliasearch from 'algoliasearch';
// For the search only version
// import algoliasearch from 'algoliasearch/lite';
const client = algoliasearch('appId', 'AdminApiKey');
const index = client.initIndex('profiles');
I haven't written any Algolia function yet, so I know that the error comes from this initialisation. (My other non-Aloglia cloud functions are running fine). And the Algolia search function installed automatically as a Firebase extension works fine too.
This is the error I get in the terminal when trying to deploying the cloud functions:
Function failed on loading user code. This is likely due to a bug in the user code. Error message: Error: please examine your function logs to see the error cause: https://cloud.google.com/functions/docs/monitoring/logging#viewing_logs. Additional troubleshooting documentation can be found at https://cloud.google.com/functions/docs/troubleshooting#logging. Please visit https://cloud.google.com/functions/docs/troubleshooting for in-depth troubleshooting documentation.
Functions deploy had errors with the following functions:
writeToFirestore(us-central1)
i functions: cleaning up build files...
Error: There was an error deploying functions
Thank you for any help!
So in the end the problem was that I had not installed the algoliasearch package in the Firebase Cloud Functions directory but in the parent (root) directory of the app.

Deploying firebase cloud function fails when I initialise firebase with a service account key

so very recently I started using google's firebase cloud functions, and loved it immediately! I very quickly restructured a project I was going to work on, and included firebase in it, so I could use the cool features of firestore, in combination with cloud functions.
Up until today, everything went on smoothly; pretty much, until I decided to play with google's FCM (Firebase Cloud Messaging) to send notifications via node js. Before this, I had created some really dense functions and already deployed to my console which were working seamlessly.
The tricky part is, at the time I created and deployed these functions, I initialised my firebase app in node js with admin.initalizeApp().
With this, everything worked fine(both locally & deployed) until I tried to use admin.messaging().sendToDevice... which resulted in a very nasty error, that basically told me I couldnt send notifications if I wasnt authenticated..
The error
(Error: An error occurred when trying to authenticate to the FCM servers. Make sure the credential used to authenticate this SDK has the proper permissions. See https://firebase.google.com/docs/admin/setup for setup instructions. Raw server response: "<HTML>
> <HEAD>
> <TITLE>Unauthorized</TITLE>
> </HEAD>
> <BODY BGCOLOR="#FFFFFF" TEXT="#000000">
> <H1>Unauthorized</H1>
> <H2>Error 401</H2>
> </BODY>
> </HTML>
> ". Status code: 401.)
Following the error, I used a few tips from some other users on stack overflow who had faced this error, and most of them suggested that I download a service key from my console, and initialise my firebase app with admin.initializeApp({credential:admin.credential.cert(serviceAccount)})
This solution worked beautifully, as it allowed me to test my notification without seeing the above error ever again.
However, when all my tests were done, and I was ready to deploy, the new function I had just created to work on notification, as well as all my previously deployed functions could not get deployed. All of a sudden, the old working functions in my console had a red exclamation mark beside them, and I had to get rid of them. Even after I cleared out all of my console and tried to redeploy all my functions, it failed, and failed and failed with no errors(context: I wasted the whole day!!! lool!) Every tip on the internet failed for me, until I reverted back to my old way of initialising my firebase app admin.initializeApp(), then booom! all my functions uploaded successfully, and then again, the authentication error appeared again when I tried to retest my notification function.....
I guess my question is: is there anything I don't know about deploying functions to the firebase console with my app initialised with a service account key I downloaded from my console?
Is there something else I need to do to get my functions to deploy properly every time I init my firebase admin app with a service account key?? Because initialising the app with just .initalizeApp() works fine for all other purposes both locally and when deployed, except when using FCM. Can anyone please help with what is happening here??
I think it can be solved by initializing two apps and using them as objects described here. One with credentials that work for other functions and one for messaging.
If you need it only for one function you can do it even inside it. I have tested it like this:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp({
credential: admin.credential.applicationDefault()
});
exports.first_app = functions.https.onRequest(async (req, res) => {
res.json(admin.app().name);
})
exports.other_app = functions.https.onRequest(async (req, res) => {
var otherApp = admin.initializeApp({
credential: **<< different credential here >>**
}, "2nd_app");
res.json(otherApp.name);
})
as already mentioned, you should initialize a second app just for the new function you are creating. You should put the initialization code inside the new function like this
export const saveMap = functions.https.onRequest(async (req, response) => {
const serviceAccount = require("./../serviceAccountKey.json");
admin.initializeApp({
projectId: "serviceAccount.project_id",
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://your_project_id_here.firebaseio.com", //update this
storageBucket: "your_bucket_name_here.appspot.com" //update this
}, "2nd_app")
I had the same issue and once I put the second initialization code into the new function, it worked. Note that in this code the serviceAccountKey.json is in the same folder as src and lib.

Why is Google Cloud Functions throwing a "Invalid value for config firebase.databaseURL" error when I try to initialize a firebase app?

I have a Google Cloud Function that syncs presence information from a Firebase realtime database to a Firestore database (as explained here). This is the relevant Cloud Functions code from the linked example:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
// Since this code will be running in the Cloud Functions enviornment
// we call initialize Firestore without any arguments because it
// detects authentication from the environment.
const firestore = admin.firestore();
// Create a new function which is triggered on changes to /status/{uid}
// Note: This is a Realtime Database trigger, *not* Cloud Firestore.
exports.onUserStatusChanged = functions.database.ref('/status/{uid}').onUpdate(
(change, context) => {
// Get the data written to Realtime Database
const eventStatus = change.after.val();
// Then use other event data to create a reference to the
// corresponding Firestore document.
const userStatusFirestoreRef = firestore.doc(`status/${context.params.uid}`);
// It is likely that the Realtime Database change that triggered
// this event has already been overwritten by a fast change in
// online / offline status, so we'll re-read the current data
// and compare the timestamps.
return change.after.ref.once('value').then((statusSnapshot) => {
const status = statusSnapshot.val();
console.log(status, eventStatus);
// If the current timestamp for this data is newer than
// the data that triggered this event, we exit this function.
if (status.last_changed > eventStatus.last_changed) {
return null;
}
// Otherwise, we convert the last_changed field to a Date
eventStatus.last_changed = new Date(eventStatus.last_changed);
// ... and write it to Firestore.
return userStatusFirestoreRef.set(eventStatus);
});
});
I recently received an email from Google informing me that I will need to update from NodeJS 6 to NodeJS 8 or 10. As this particular function isn't in production yet, I went ahead and made the configuration change in the Google Cloud Console. I now get the error below. I tried switching back to NodeJS 6, recreating the function from scratch, checking Github issues and other online forums. It appears that my Google Cloud Function is no longer being provided with the necessary environment variables to connect with Firebase/Firestore. However, I'm unsure why that would be the case.
Error: Invalid value for config firebase.databaseURL: undefined
at resourceGetter (/srv/node_modules/firebase-functions/lib/providers/database.js:101:19)
at cloudFunctionNewSignature (/srv/node_modules/firebase-functions/lib/cloud-functions.js:102:13)
at /worker/worker.js:825:24
at <anonymous> at process._tickDomainCallback (internal/process/next_tick.js:229:7)
This error also shows up in the Stackdriver logs for the Cloud Function:
Warning, estimating Firebase Config based on GCLOUD_PROJECT. Initializing firebase-admin may fail
You should redeploy using the Firebase CLI. It does some special things in the environment to help the Firebase Admin SDK initialize correctly without any parameters (adding FIREBASE_CONFIG). It sounds like when you changed the runtime in the console, you also lost this special configuration.
For me, I use firestore, and I was getting the same error as you, so I had to create a real-time database without any record then I set the credentials for the admin like so:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp({
databaseURL: "your realtime database url"
});
When you are done, run firebase deploy --only functions to deploy your functions.
Here is your Realtime database URL:

Firebase Admin INVALID_APP_OPTIONS error at initializeApp()

I'm trying to connect Instagram OAuth to Firebase through Node.js back-end. I have successfully retrieved Instagram account data including access_token which I want to exchange with firebase-admin's createCustomToken on my Node.js backend. My objective here is to generate custom token so my Angular app can do signInWithCustomToken(token) into my Firebase app. There is no problem on retrieving data from Instagram as I can print my JSON object on console.
The problem is occurred when I want to exchange my access_token to Firebase Custom Token.
I have followed this guide from Firebase Admin page for Node.js and I'm facing an error message below
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_APP_OPTIONS, "Invalid Firebase app options passed as the first argument to initializeApp() for the " +
Error: Invalid Firebase app options passed as the first argument to initializeApp() for the app named "[DEFAULT]". The "credential" property must be an object which implements the Credential interface.
Here is my code on related issue.
// authService.js
var fbAdmin = require('firebase-admin');
var serviceAccount = require('./key/key.json');
function createFirebaseToken(instagramID) {
// I copy & pasted this var from other class
var config = {
apiKey: "MY_FIREBASE_APIKEY",
authDomain: "MY_APP.firebaseapp.com",
databaseURL: "https://MY_APP.firebaseio.com",
storageBucket: "MY_APP.appspot.com",
};
console.log(fbAdmin.credential.cert(serviceAccount)); // serviceAccount successfully printed on console
// Error appears when executing this function
fbAdmin.initializeApp({
serviceAccount: fbAdmin.credential.cert(serviceAccount),
databaseURL: config.databaseURL
});
const uid = `instagram:${instagramID}`;
// Create the custom token.
console.log(uid);
return fbAdmin.auth().createCustomToken(uid);
}
It appears that my Node app cannot initialize a connection to firebase-admin but I have no idea the solution as I am a beginner on these technologies. Please advice.
This issue can be resolved by updating firebase-tools, firebase-functions and firebase-admin packages to the latest version.
npm install -g firebase-tools#latest
npm install firebase-functions#latest
npm install firebase-admin#latest
Refer this GitHub page for more details.
Just stumbled upon on Firebase Admin Release Notes at version 5.0.0 on May 2017 stated that serviceAccount has been removed. So instead of forcing to use serviceAccount, I use credential instead.
fbAdmin.initializeApp({
credential: fbAdmin.credential.cert({
projectId: '<APP_ID>',
clientEmail: "foo#<APP_ID>.iam.gserviceaccount.com",
privateKey: "-----BEGIN PRIVATE KEY-----\n<MY_PRIVATE_KEY>\n-----END PRIVATE KEY-----\n"
}),
databaseURL: config.databaseURL
});
Updated Answer
After continuing to work with this, it seems to be able to call admin.initializeApp() without any params, you need to make sure your `/functions nodeJs setup is up to date.
In /functions directory, run this command:
npm i --save firebase-functions#latest
Thanks to:
https://stackoverflow.com/a/49437619/2162226
.. I am still getting familiar with all the nodeJS/npm details - not sure why, but seems I had to run it a few times for everything to get into place. That and the sudo npm install -g firebase-tools updated as well .
According to official docs, we need to be using at least version Firebase 4.12.0 in order to get the latest cloud functions support: https://firebase.google.com/docs/functions/callable
First Answer
I ran into the same error message in trying to set up Cloud Functions for Firebase.
Passing in the argument for admin.initializeApp solved it for my project:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
After a good amount of search, gratefully found this thread with a post where it has that line of code: https://github.com/firebase/firebase-functions/issues/99 .. because so far haven't seen it anywhere in the docs about that parameter
According to the release docs for Jan. 11, 2018:
https://firebase.google.com/support/release-notes/admin/node
The admin.initializeApp() method can now be invoked without any arguments. This initializes an app using Google Application Default Credentials, and other AppOptions loaded from the FIREBASE_CONFIG environment variable.
Kindly use the following snippet, which is mentioned in the Firebase Admin SDK for Node.js. Download the JSON file from the Service Account in the Project Settings and change the path in serviceAccount. Also add your databaseUrl, which is of the form http://app_name/.firebaseio.com
var admin = require("firebase-admin");
var serviceAccount = require("path/to/serviceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "yourDatabaseUrl"
});
For those having this issue with "firebase-admin": "^11.0.0", you have to construct the certification passed into initializeApp() using cert imported from firebase-admin/app.
Example:
import { initializeApp, cert } from "firebase-admin/app";
const admin = initializeApp({
credential: cert({
projectId: process.env.MY_PROJECT_ID,
clientEmail: process.env.MY_PRIVATE_KEY,
privateKey: process.env.MY_CLIENT_EMAIL,
}),
});
Check what version of firebase-admin module you are using.
As per the release note of version 5.9.1
The admin.initializeApp() method can now be invoked without a credential option. The SDK uses Google Application Default Credentials when initialized this way.
release notes

Firebase Node.js admin SDK timeouts when trying to access Realtime DB

Using the Node.js admin SDK with Firebase Functions I get a timeout whenever I try to access the Realtime Database. This occurs only when testing a function locally (firebase serve --only functions,hosting) and when the default app is initialized using the functions.config().firebase.
This is a new behavior that started just a couple a days ago. However, if I try to initialize the default app with the serviceAccount.json file everything works as expected.
I'm using firebase-admin version 4.2.1 and firebase-functions version 0.5.9.
I wrote a straight forward http triggered function that fails due to timeout:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const db = admin.database();
exports.testDbConnection = functions.https.onRequest((req, res) => {
return admin.database().ref().once('value')
.then(function(snapshot) {
res.json(snapshot);
}).catch(function(error) {
res.json(error);
});
});
from the documentation
Always end an HTTP function with send(), redirect(), or end(). Otherwise, your function might to continue to run and be forcibly terminated by the system
see https://firebase.google.com/docs/functions/http-events#terminate_http_functions
This might depend on the firebase-tools version that you are using, but looks familiar to this Github issue
The solution for it is to either upgrade to the latest version of the CLI or use the workaround solution:
Go to https://cloud.google.com/console/iam-admin/serviceaccounts
Click “Create service account”, give it a name (e.g. emulator), give it the Project>Owner role.Check “Furnish a new private key”, pick “JSON”.
Save the file somewhere on your computer
Run export GOOGLE_APPLICATION_CREDENTIALS="absolute/path/to/file.json"
Run firebase serve --only functions

Resources