firebase cannot determine project id - node.js

this is the request that I made using node
// Initialize the default app
var admin = require('firebase-admin');
var app = admin.initializeApp({
credential: admin.credential.applicationDefault(),
databaseURL: process.env.FIREBASE_DATABASE
});
console.log(process.env.FIREBASE_DATABASE);
router.post('/', (req, res, next) => {
app.auth().getUserByEmail("j.100233260#gmail.com")
.then(function(userRecord) {
// See the UserRecord reference doc for the contents of userRecord.
console.log('Successfully fetched user data:', userRecord.toJSON());
res.json(userRecord.toJSON())
})
.catch(function(error) {
console.log('Error fetching user data:', error);
res.json(error)
});
}
);
I set the env var on my machine
for my firebase database I used env
given as
databaseURL: "https://fssssss.firebaseio.com",
from the firebase admin GUI ,
the error in Postman when I request this route
{
"code": "app/invalid-credential",
"message": "Failed to determine project ID: Error while making request: getaddrinfo ENOTFOUND metadata.google.internal metadata.google.internal:80. Error code: ENOTFOUND"
}
I followed the docs and google returned no results, no idea what to do. thanks.

This isn't working the way you expect:
admin.credential.applicationDefault()
You can't use this on a server that you control without additional configuration. This only works by itself when running on Google services when you want to use the default service account for your project. When running on your own server, there is no default. You have to be explicit and download service account credentials to use during initialization. At the very least, you'll need to follow the instructions in the documentation:
To authenticate a service account and authorize it to access Firebase
services, you must generate a private key file in JSON format.
To generate a private key file for your service account:
In the Firebase console, open Settings > Service Accounts.
Click Generate New Private Key, then confirm by clicking Generate Key.
Securely store the JSON file containing the key.
When authorizing via a service account, you have two choices for
providing the credentials to your application. You can either set the
GOOGLE_APPLICATION_CREDENTIALS environment variable, or you can
explicitly pass the path to the service account key in code. The first
option is more secure and is strongly recommended.
So you will need to download the service account file, set GOOGLE_APPLICATION_CREDENTIALS correctly, then your code will work. The service account credentials are not optional.

Method 1: Just pass the path of your service account key
const firebase_admin = require('firebase-admin');
const serviceAccount = require("/path/to/yourserviceaccountkey.json");
const admin = firebase_admin.initializeApp({
credential: firebase_admin.credential.cert(serviceAccount);
});
Method 2 (more secure): The method above is considered less secure than the method below:
const firebase_admin = require('firebase-admin');
const admin = firebase_admin.initializeApp({
credential: admin.credential.applicationDefault()
});
Then run the app like this:
GOOGLE_APPLICATION_CREDENTIALS=/path/to/yourserviceaccountkey.json node index.js
Or through a package.json script:
"start" : "GOOGLE_APPLICATION_CREDENTIALS=/path/to/yourserviceaccountkey.json node index.js"
You can also set the environmental variable likes this in a terminal session, before you run Node:
export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"
References
Add the Firebase Admin SDK to your server

If you followed the instructions for initializing the SDK by setting the environment variable using this command:
export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"
You may have to double check that the name of the service account file matches the path you downloaded.
For example when I downloaded the service-account-file.json, mine was named my-firebase-project.json, but I used the export command without updating the filename.
Once that was fixed, the issue disappeared.

You need to add projectId
admin.initializeApp({
credential: admin.credential.applicationDefault(),
projectId: `xxx-xxxxxx-xxx`, // this line
databaseURL: environment.firebaseDbUrl
});
Note: You'll get the projectId from firebase project settings page. See image

Reason why you are getting this error even after setting the GOOGLE_APPLICATION_CREDENTIALS environment variable correctly is because it needs to be set in every session when you run the firebaseAdmin initialize method. Hence you should set it every time using below in your package.json file:
"scripts": {
"build": "npx tsc",
"start": "export GOOGLE_APPLICATION_CREDENTIALS=/Users/abc/Documents/Code/my_folder/my_app_6abcd31ffa3a.json npm run build && ts-node index.ts",
"test": "test"
},

Related

Authenticating as a service account outside of the Google Cloud environment using firebase-admin

I'm having trouble on authenticating as a service account in my Next.js app hosted on Vercel. My code is working fine in my dev environment, but it fails with the following error message when I try to run it on Vercel Node.js v14 environment. I guess that it runs on my local machine because I'm logged in gcloud with my email (project owner).
This is the error I'm getting:
Error: Could not load the default credentials. Browse to https://cloud.google.com/docs/authentication/getting-started for more information.
at GoogleAuth.getApplicationDefaultAsync (/var/task/node_modules/google-auth-library/build/src/auth/googleauth.js:173:19)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async GoogleAuth.getClient (/var/task/node_modules/google-auth-library/build/src/auth/googleauth.js:551:17)
at async GrpcClient._getCredentials (/var/task/node_modules/google-gax/build/src/grpc.js:109:24)
at async GrpcClient.createStub (/var/task/node_modules/google-gax/build/src/grpc.js:252:23)
I've created the following service account to use it with my Next.js APIs.
It has all the necessary roles. I've created a JSON key and download it.
I'm using firebase-admin and this is how I'm initializing it:
export const initializeFirebaseAdmin = (): FirebaseAdmin => {
const account = getServiceAccount(); // THIS IS THE SERVICE ACCOUNT JSON KEY (ALREADY PARSED AS AN OBJECT)
if (!admin.apps.length) {
admin.initializeApp({
credential: admin.credential.cert(account),
});
}
return admin;
};
This is what I think it's happening:
From: https://cloud.google.com/docs/authentication/production#automatically
From the image above:
I'm not setting any GOOGLE_APPLICATION_CREDENTIALS environment variable
So I should be on number 2. It will "try to use the service account that is attached to the resource that is running your code."
It's obviously failing and I getting the error
But which resource is it referring to? Which code?
The resource that is running my code is Firebase Admin? Am I not initializing it correctly?
This code should work to authenticate the firebase-admin package:
export const initializeFirebaseAdmin = (): FirebaseAdmin => {
const account = getServiceAccount(); // THIS IS THE SERVICE ACCOUNT JSON KEY (ALREADY PARSED AS AN OBJECT)
if (!admin.apps.length) {
admin.initializeApp({
credential: admin.credential.cert(account),
});
}
return admin;
};
My problem was related to the fact that I was using a client exposed from the firebase-admin package, that doesn't have access to the authentication from the main package. So I needed to pass the credentials to it as well. Like:
const client = new admin.firestore.v1.FirestoreAdminClient({
credentials: SERVICE_ACCOUNT as CredentialBody // <<<<<< THIS IS THE SERVICE ACCOUNT JSON KEY
});
Refer also to: Trying to export backup via admin.firestore.v1.FirestoreAdminClient on a Next.js API route. Error: Could not load the default credentials

Using firebase-admin. What are service account credentials used for?

I'm building a cloud function to get some documents and generate an HTML response.
And right now what I have is:
myFunction.js
import * as admin from 'firebase-admin';
import serviceAccount from './someServiceAccountKey.json';
// OPTION #1 <-----
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://myfirebaseproject.firebaseio.com"
});
// OPTION #2 <------
admin.initializeApp();
// FUNCTION <------
async function(req,res) {
const docSnapshot = await admin.firestore().collection('someCollection').doc('someDoc').get();
// AND SO ON...
}
At some point I've created that serviceAccount key (I don't remember from which tutorial) and I've been using on my functions to "grant access" to the firebase-admin (as in OPTION #1 from the code above). Because I thought I needed to.
But I've found out that even without any initializing parameter or serviceAccount credential (as in OPTION #2 from the code above), I can initialize the firebase-admin and access my firebase project resources (like Firestore) without any issues.
And I can do this on deployed functions, which makes sense, since they are inside the Firebase project's cloud environment, and if they were deployed, they should have access to the project's resources, without the need for a service account, right?
But I also found out that I can do this in my Node.js local environment. By calling the function with npx babel-node myFunction.js (using babel node to transpile and execute). The function is able to access and query my Firestore (on-line data, this is not the Firestore emulator) without any issues.
Where is my local environment getting permission to access my project's resources from? Is it from the firebase-tools that is installed and logged in my project?
If I don't need them in both cases. What are service accounts mainly used for?
You initialize SDK in different way depending on the environment:
Cloud Functions
const admin = require('firebase-admin');
const functions = require('firebase-functions');
admin.initializeApp(functions.config().firebase);
let db = admin.firestore();
Google Cloud Platform
const admin = require('firebase-admin');
admin.initializeApp({
credential: admin.credential.applicationDefault()
});
const db = admin.firestore();
// ...
Node server
const admin = require('firebase-admin');
let serviceAccount = require('path/to/serviceAccountKey.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
let db = admin.firestore();
Look here for more details
So, your observations are correct.
However, since even using OPTION #2 you are getting access to your firebase, then most likely you need to check your database rules and make sure you are prohibiting unauthenticated access to your db.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth.uid != null;
}
}
}
More about the rules here.
Firebase data is secured using rules, before you set up any rules, any user (even unauthenticated) can access your data.
https://firebase.google.com/docs/rules/basics
Once you have rules set up, then either the user or the server will have to authenticate in order to read/write data.
Users authenticate by logging on with google (or whatever client side security you have ocnfigured).
Servers authenticate by using the service account. Service accounts default to having admin access to the database.
https://firebase.google.com/docs/database/admin/start#authenticate-with-admin-privileges

Nodejs cloud vision api PERMISSION_DENIED wrong project #

when I try to run firebase functions with cloud vision API and test the functions. I get this error:
ERROR: { Error: 7 PERMISSION_DENIED: Cloud Vision API has not been
used in project 563584335869 before or it is disabled. Enable it by
visiting
https://console.developers.google.com/apis/api/vision.googleapis.com/overview?project=563584335869
then retry. If you enabled this API recently, wait a few minutes for
the action to propagate to our systems and retry.
I do not recognize this project number and I have already enabled the API with the project that I am using. I set the GOOGLE_APPLICATION_CREDENTIALS using the project with the enabled API. What is it that I'm doing wrong?
For those of you who are still having this issue here is what worked for me:
const client = new vision.ImageAnnotatorClient({
keyFilename: 'serviceAccountKey.json'
})
This error message is usually thrown when the application is not being authenticated correctly due to several reasons such as missing files, invalid credential paths, incorrect environment variables assignations, among other causes.
Based on this, I recommend you to validate that the credential file and file path are being correctly assigned, as well as follow the Obtaining and providing service account credentials manually guide in order to explicitly specify your service account file directly into your code; In this way, you will be able to set it permanently and verify if you are passing the service credentials correctly. Additionally, you can take a look on this link that contains a useful step-by-step guide to use Firebase functions with Vision API which includes the Vision object authentication code for Node.js.
Passing the path to the service account key in code example:
// Imports the Google Cloud client library.
const Storage = require('#google-cloud/storage');
// Instantiates a client. Explicitly use service account credentials by
// specifying the private key file. All clients in google-cloud-node have this
// helper, see https://github.com/GoogleCloudPlatform/google-cloud-node/blob/master/docs/authentication.md
const storage = new Storage({
keyFilename: '/path/to/keyfile.json'
});
// Makes an authenticated API request.
storage
.getBuckets()
.then((results) => {
const buckets = results[0];
console.log('Buckets:');
buckets.forEach((bucket) => {
console.log(bucket.name);
});
})
.catch((err) => {
console.error('ERROR:', err);
});
API has not been used in project 563584335869
If you clicked that link has been printed in a console, that guide you to this url.
https://console.developers.google.com/apis/api/vision.googleapis.com/overview?project=firebase-cli
So that project id means you used the project credential of 'firebase-cli' not yours.
If you tried to set the value of the environment, you can find the variables in your directory
~/.config/firebase/...credentials.json
And sometime it would be not replaced after you tried to override.
But, you can set your credential in code.
You can find the way of getting a credential in here.
https://cloud.google.com/iam/docs/creating-managing-service-account-keys
And the credential format is like this one.
{
"type": "service_account",
"project_id":
"private_key_id":
"private_key":
"client_email":
"client_id":
"auth_uri":
"token_uri":
"auth_provider_x509_cert_url":
"client_x509_cert_url":
}
I've faced exactly the same error what you have when I used another google API. and resolved that way including the credential inside code.
const textToSpeech = require("#google-cloud/text-to-speech")
const keyfile = require(".././my-project.json")
const config = {
projectId: keyfile.project_id,
keyFilename: require.resolve(".././my-project.json")
};
const TTS_Client = new textToSpeech.TextToSpeechClient(config)

Firebase: How to verify Google login token id from Android & iOS

I want to verify on my node backend all the tokens (Google login) i get from my Android app. I started with initializing the firebase module like this:
var admin = require('firebase-admin');
var serviceAccount = require('googlefirebase');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: url
});
This gave me some error about some DEFAULT name and i found out that i needed to use this code:
var admin = require('firebase-admin');
var serviceAccount = require('googlefirebase');
admin.initializeApp(functions.config().firebase);
Then i realize that i need to install and init the project on my server so i did this:
firebase login
firebase init
firebase use --add project
firebase functions:config:set "google-services.json" (just the project_info data of the json that i downloaded from firebase)
Now i get this error:
Error: Must initialize app with a cert credential or set your Firebase
project ID as the GOOGLE_CLOUD_PROJECT environment variable to call
verifyIdToken()
EDIT START
I get this error when i call:
admin.auth().verifyIdToken(token).then(function(decodedToken) {}.catch(){};
EDIT END
I already "init" firebase (or at least i thing so) and created the environment variables: GOOGLE_CLOUD_PROJECT and FIREBASE_CONFIG and i keep getting the same error.
So, whats the right way to get firebase to work? what am i missing? is verifyIdToken the right method to verify the token? i just want to verify the google login token.
With Cloud Functions for Firebase, you're not supposed to initialize like this any more:
admin.initializeApp(functions.config().firebase);
You're supposed to use no arguments:
admin.initializeApp();
Also, your google-services.json file is not useful in Cloud Functions. That's only for use in an Android app.
you should have a FIREBASE_CONFIG environments variable and then call
// Initialize the default app
var admin = require('firebase-admin');
var app = admin.initializeApp();
that config variable contain the initialize information like :
databaseURL: 'https://databaseName.firebaseio.com',
storageBucket: 'projectId.appspot.com',
projectId: 'projectId'

FIREBASE WARNING: Provided authentication credentials are invalid

I am trying to use Firebase in node.js but every time I restart the server I am getting following error:
FIREBASE WARNING: Provided authentication credentials are invalid. This usually indicates your FirebaseApp instance was not initialized correctly. Make sure your apiKey and databaseURL match the values provided for your app at https://console.firebase.google.com/, or if you're using a service account, make sure it's authorized to access the specified databaseURL and is from the correct project.
Following is my index.js:_
var express = require('express');
var router = express.Router();
var mongoose=require('mongoose');
var admin=mongoose.model('admin');
var firebase = require("firebase");
// Initialize the app with no authentication
firebase.initializeApp({
serviceAccount: {
projectId: "...",
clientEmail: "...",
privateKey: "-----BEGIN PRIVATE KEY-----...",
},
databaseURL: "..."
});
console.log("sfsaf")
// The app only has access to public data as defined in the Security Rules
var db = firebase.database();
var ref = db.ref("unitalk-b9145");
var messagesRef = ref.child("messages");
messagesRef.push({
name:"Rupali",
post:"Demo test of firebase"
});
Although I have checked the path of service-account and databaseURl..
Please help..
You can not log in with the service account using the "firabase" package. You need to use the "firabase-admin" package for this. You can find detailed information here (https://firebase.google.com/docs/database/admin/start).
UPDATED: 8 Nov 2016
go to : https://console.firebase.google.com
To use the Firebase Admin SDKs, you'll need a Firebase project, a service account to communicate with the Firebase service, and a configuration file with your service account's credentials.
Navigate to the Service Accounts tab in your project's settings
page.
Select your Firebase project. If you don't already have one, click
the Create New Project button. If you already have an existing
Google project associated with your app, click Import Google Project
instead.
Click the Generate New Private Key button at the bottom of the
Firebase Admin SDK section of the Service Accounts tab.
After you click the button, a JSON file containing your service
account's credentials will be downloaded. You'll need this to
initialize the SDK in the next step.
Sample code;
var admin = require("firebase-admin");
var serviceAccount = require("path/to/serviceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://<DATABASE_NAME>.firebaseio.com"
});
Another method to solve the issue link
for those who still facing this issue, you may try on this method, this is related to the project roles management according to the description inside
For anyone looking at this recently. I had the problem with Firebase function, after changing project. It went away when i removed the keys from admin.initializeApp()
Apparently firebase functions now know to use the project credentials. So just this;
admin.initializeApp();
You are using require('firebase') module so u need the following things:
var config = {
apiKey: " [your api key]",
authDomain: "[projectname].firebaseapp.com",
databaseURL: "https://[projectname].firebaseio.com/",
storageBucket: "[projectname].appspot.com",
messagingSenderId: "[message id]",
};
firebase.initializeApp(config);
If you want to use require("firebase-admin") then you have to configure
serviceAccountKey.json(downloaded file) file ...
I am able to connect with firebase successfully.

Resources