Error while initializing Service Account key - firebase

When I try to initialize my service account key like so:
const admin = require('firebase-admin');
const serviceAccount = require("./serviceAccountKey.json");
// Initialize the Firebase Storage admin constant
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
storageBucket: "<DATABASE-NAME>.appspot.com",
databaseURL: "https://<DATABASE-NAME>.firebaseio.com"
});
I get the following error Error parsing triggers: Cannot find module './serviceAccountKey.json'
My serviceAccountKey.json file is inside my project name folder.
Also my dependencies from Firebase are the following:
"dependencies": {
"firebase": "^6.5.0",
"firebase-admin": "8.4.0",
"firebase-functions": "^3.2.0"
},
My directory structure is the following:
-server
-idea
-bin
-functions
-node_modules
-public
-routes
-views
-.firebaserc
-.gitignore
- app.js
- firebase.json
- master
- package.json
- package-lock.json
- serviceAccountKey.json ===> ***
- server.iml
Why am I getting this error?
Note: I've done some research on this and my file path does conform with the node.js documentation on using the require method.

Put your serverAccountKey.json file in your "functions" folder. The entire contents of that gets packaged up and sent to Cloud Functions (unless you changed that default in firebase.json). Files that are outside that folder will not be available. Right now, it looks like the file is in "server".

Related

FirebaseProjectNotFoundException: Firebase project id could not be found on this Firebase account

I found this project. After I added to index.html file the following Firebase configuration:
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script type="module">
// Import the functions you need from the SDKs you need
import { initializeApp } from "https://www.gstatic.com/firebasejs/8.6.1/firebase-app.js";
import { initializeApp } from "https://www.gstatic.com/firebasejs/8.6.1/firebase-auth.js";
import { initializeApp } from "https://www.gstatic.com/firebasejs/8.6.1/firebase-firestore.js";
import { initializeApp } from "https://www.gstatic.com/firebasejs/8.6.1/firebase-storage.js";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
const firebaseConfig = {
apiKey: "AIzaSyDoO8efzrDVveeXvqqrc39D3XiqfsyoKeU",
authDomain: "diary-app-course-c6663.firebaseapp.com",
projectId: "diary-app-course-c6663",
storageBucket: "diary-app-course-c6663.appspot.com",
messagingSenderId: "1031493909898",
appId: "1:1031493909898:web:3cd71413645447b67c1c73"
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
</script>
Next, I did the following steps on command line:
$ dart pub global activate flutterfire_cli
Warning: Pub installs executables into $HOME/.pub-cache/bin, which is not on your path.
You can fix that by adding this to your shell's config file (.bashrc, .bash_profile, etc.):
export PATH="$PATH":"$HOME/.pub-cache/bin"
$ vim ~/.bashrc
$ source ~/.bashrc
$ flutterfire configure
$ curl -sL https://firebase.tools | bash
Unfortunately, I got this error:
$ flutterfire configure
i Found 1 Firebase projects. Selecting project diary-app-course.
FirebaseProjectNotFoundException: Firebase project id "diary-app-course" could not be found on this Firebase account.
$ grep -R diary-app-course *
web/index.html: authDomain: "diary-app-course-c6663.firebaseapp.com",
web/index.html: projectId: "diary-app-course-c6663",
web/index.html: storageBucket: "diary-app-course-c6663.appspot.com",
What did I miss?
Follow these steps:
Remove if their any default project exists in .firebaserc file.
Before:
{
"projects": {
"default": "diary-app-course"
}
}
After
{
"projects": {
}
}
Run this command in Firebase CLI:
firebase logout
Log in again:
firebase login
Again run this command in Firebase CLI
flutterfire configure
Hope this works.
flutterfire configure --project=diary-app-course-c6663
You could see your project id on your firebase link
for example : https://console.firebase.google.com/u/0/project/ this is your project id/database/xxxx/data
So, I made some change: If you are trying to logging in one account for registering firebase while creating new project, and at that time but if your android studio account was another one it will be problem.
Make sure to use one gmail account for registering new project and login that entered project
LOG OUT and LOG IN again
Please choose default account and create

Emulator Storage running but ignored

I have a firebase function that is successfully uploading a file when run in the emulator, but the file ends up on production even though I'm running the Storage Emulator
I'm running with the following package.json snippets in the functions directory
"dependencies": {
"firebase-admin": "^8.13.0",
"firebase-functions": "^3.16.0",
...
}
"engines": {
"node": "14"
}
I'm initializing everything with defaults (which has worked fine in emulation and production until recently).
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const storage = admin.storage();
const bucket = storage.bucket();
...
const myFunction = async () => {
const savedFile = await bucket.file(`99999999.html`).save(fileContents);
}
The code above works, although the file ends up on production, not in the emulator storage. The logs show that a production google api is being accessed.
This would be fine (not ideal, but workable) if I could also read the file. But when I try to run the .exits() or .download() function for the same file with bucket.file('99999999.html').download();, I get the following log entries:
I need to either:
Get emulation for storage working to resolve this (ideal)
Figure out why downloading isn't working in this case
If anyone can help me with either, I'd greatly appreciate it.
I have updated firebase-admin and firebase-tools packages accordingly:
"dependencies": {
"firebase-admin": "^10.0.0",
"firebase-tools": "^9.23.1",
...
}
This resulted in a more clear error saying that the file downloaded did not match the file on the server (a hash mismatch from what I understand). I know that this is not the case, so I changed .download() to .download({validation: false}). This resolved my issue with accessing the file. It is still not storing on local emulation, but maybe that's not the intent.
UPDATE: I figured out you have to change the bucket to see your files in emulated storage.

Firebase admin looking for a different default project than the one I'm currently working on my local environment

I'm building this cloud function in my local environment and I need to save something to Firestore:
Here's how I'm initializing the firebase-admin app:
myFunction.js
if (!adminHasInitialized) {
console.log("INITIALIZING ADMIN APP"); // THIS IS BEING LOGGED
admin.initializeApp({
credential: admin.credential.applicationDefault(),
});
adminHasInitialized = true;
}
And here's how I'm trying to update my Firestore:
await admin.firestore().collection("myCollection").doc("myDoc").update({
...
});
NOTE: I'm working on MY_PROJECT_1
And this is the error I'm getting:
details: 'No document to update: projects/MY_PROJECT_2/databases/(default)/documents/myCollection/myDoc',
PROBLEM
Somehow firebase-admin is looking inside another database for a different project MY_PROJECT_2 that I have.
When I run: firebase projects:list, this is what I get:
Project Display Name │ Project ID │ Resource Location ID
MY_PROJECT_1 │ MY_PROJECT_1 (current) │ us-central1
MY_PROJECT_2 │ MY_PROJECT_2 │ us-central1
So the current project is correct.
Also I have this file, which I set the default as MY_PROJECT_1
.firebaserc
{
"projects": {
"default": "MY_PROJECT_1"
}
}
I also tried to add the DB URL when I'm initializing the app, as:
admin.initializeApp({
credential: admin.credential.applicationDefault(),
databaseURL: "https://MY_PROJECT_1.firebaseio.com"
});
But I keep getting the same error.
NOTE: I'm running this function in my local environment using babel-node throught the following command:
npx babel-node functions/src/myFunction.js
QUESTION
How is firebase-admin getting a different default project than the one I'm currently working on?
UPDATE 1
I think that firebase-admin is getting the default configuration from the gcloud SDK that is installed in my PC.
From:
[C:\Users\USER\AppData\Roaming\gcloud\configurations\config_default]
config_default:
[core]
account = my#email.com
project = MY_PROJECT_2 // MAYBE IT IS COMING FROM HERE
UPDATE 2
So far, the only thing I've managed to make it work is with:
admin.initializeApp({
projectId: "MY_PROJECT_1",
databaseURL: "https://MY_PROJECT_1.firebaseio.com"
});
This gives me the correct project when I run this function locally.
Since version 1.0.0 of the Firebase SDK for Cloud Functions you don't need anymore to initialize with admin.initializeApp(functions.config().firebase);, see the doc here, which explains that:
firebase-admin is now initialized without any parameters within the
Cloud Functions runtime.
So please try with:
if (!adminHasInitialized) {
console.log("INITIALIZING ADMIN APP");
admin.initializeApp();
adminHasInitialized = true;
}

Error parsing triggers Cannot find module when deploying firebase function

I am implementing a firebase function endpoint that requires I authenticate with two different projects. Information found on SO and other sources suggest this
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
const serviceAccountSource = require('./source.json');
const serviceAccountTarget = require('./target.json');
const sourceAdmin = admin.initializeApp({
credential: admin.credential.cert(serviceAccountSource)
})
const targetAdmin = admin.initializeApp({
credential: admin.credential.cert(serviceAccountTarget)
s}, "destination")
Where source.json and target.json are files storing the serviceAccount credentials (JSON) obtained from the Project Settings => Generate New Private Key.
My folder structure is as follows
functions/
index.ts
source.json
target.json
Running the following
npm run-script lint
produces no errors, however when I run
firebase deploy --only functions
I get
Error: Error parsing triggers: Cannot find module './source.json'
Firebase admin / functions versions as follows
"firebase-admin": "7.0.0",
"firebase-functions": "^2.2.0"
Typescript
"typescript": "^3.2.2"
Any ideas as what is causing the error.
If you are using Typescript try moving your source.json to the lib folder.
I found a solution to this. Although documentation on the firebase admin functions (parameters etc) seems to be very scarce I did notice that the credential.cert member takes a ServiceAccountPathOrObject.
I tried
const sourceAdmin = admin.initializeApp({
credential: admin.credential.cert('./source.json')
})
This failed with a path not found but this time it gave the path. From this I was able to see that there was a missing element in the Path
const sourceAdmin = admin.initializeApp({
credential: admin.credential.cert('./src/source.json')
})
The function deployed. I then tried to go back to the original code and added the 'src' folder to the path - however that resulted in the same error.
I prefer the above solution but I am still interested to know what caused the original error - given that much of the documentation out there seems to recommend this including this https://gist.github.com/brunobraga95/82bef0672ce451767107e62df1d8b28f - which is the code I am trying to implement.
The function has deployed and is working - so I can confirm the recommendation above works.

Firebase configuration for multiple projects/environments

I'm using Cloud Functions for Firebase with three different projects for development, testing and production purposes. Each project has a service-account.json. When I deploy the sources to an environment, the initialization looks like this:
var serviceAccount = require("./service-account-dev.json");
firebase.initializeApp({
credential: firebase.credential.cert(serviceAccount),
databaseURL: "https://nwDEV.firebaseio.com"
});
This is a bit difficult to handle, because I have to change the code everytime I want to deploy to a different environment. Is there a way to have an overall configuration, e.g. in firebase.json or.firebasesrc, which allows to integrate the service-account and decides on deployment which configuration to choose?
Otherwise is there a possibility to detect under which environment the code is running and to load the specific service-account.json and to set the databaseURL-property?
You can use environment variables. https://firebase.google.com/docs/functions/config-env
Select the project (you can use the command firebase projects:list to see them):
firebase use my-project-development
Set an environment variable
firebase functions:config:set app.environment="dev"
In your functions file, apply a conditional to choose the file:
const serviceAccount = functions.config().app.environment === 'dev' ? 'credentials-dev.json' : 'credentials-prod.json';
Then you can use the file depending on the project:
firebase.initializeApp({
credential: firebase.credential.cert(serviceAccount),
databaseURL: "https://nwDEV.firebaseio.com"
});
From what I understand of your question, what you are looking for boils down to a solution to translate the cloud functions you are deploying to the appropriate settings, i.e. production, development, and testing, which I assume means each of these is a unique project, and therefore database, in your Firebase environment.
If the above is true then the following should help.
Firebase Cloud Functions, and CLI more generally, is able to deploy to a specific project in your Firebase environment. To do this execute the following command in the terminal while in the cloud functions directory.
$ firebase use --add
This will allow you to pick your additional project (for instance, development) and assign it an alias (I recommend "development" if it is as such). Then when deploying your functions you can choose which project (and therefore database) to deploy to by using the alias.
$ firebase use default # sets environment to the default alias
$ firebase use development # sets environment to the development alias
For more information please see: https://firebase.googleblog.com/2016/07/deploy-to-multiple-environments-with.html
One thing you may have to do for this to work would be to use the default config settings for Cloud Functions.
$ admin.initializeApp(functions.config().firebase);
Short answer:
the GCLOUD_PROJECT environment variable will be unique to your project, hence you can utilise it like this (sample code is for 2 different projects but you can extend it using switch or any other conditional statement):
const env = process.env.GCLOUD_PROJECT === 'my-app-prod' ? 'prod' : 'dev';
then use that env variable to load intended configuration.
Full example: (TypeScript)
update .firebaserc file
{
"projects": {
"default": "my-app-dev",
"prod": "my-app-prod",
}
}
create and modify your ./somewhere/config.ts file accordingly, let's say you're using AWS services (please ensure to secure your configuration details)
export const config = {
dev: {
awsRegion: 'myDevRegion',
awsAccessKey: 'myDevKey',
awsSecretKey: 'myDevSecretKey'
},
prod: {
awsRegion: 'myProdRegion',
awsAccessKey: 'myProdKey',
awsSecretKey: 'myProdSecretKey'
}
};
now above items can be used in the index.ts file
import { config } from './somewhere/config';
import * as aws from 'aws-sdk';
. . .
const env = process.env.GCLOUD_PROJECT === 'my-app-prod' ? 'prod' : 'dev';
const awsCredentials = {
region: config[env].awsRegion,
accessKeyId: config[env].awsAccessKey,
secretAccessKey: config[env].awsSecretKey
};
aws.config.update(awsCredentials);
. . .
export const myFuncToUseAWS = functions....
Now the deployment
Dev environment deployment: $ firebase deploy --only functions -P default
Prod environment deployment: $ firebase deploy --only functions -P prod

Resources