Firebase Node SDK ref.on and ref.once not working - firebase

I've been using firebase for a couple years now and I've not run into this - I believe it is Google Account/Firebase Account related.
This basic code will not get into the ref.on() or ref.once() function - either the success or error callbacks. What is the deal?
var firebase = require('firebase');
var admin = require('firebase-admin');
const serviceAccount = require('../firebase-security.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: 'https://swc-shockball3.firebaseio.com/'
});
var db = admin.database();
console.log('trying to get ref .once')
var itemsRef = db.ref('items');
itemsRef.once('value', function(snapshot) {
// never gets here
console.log(snapshot)
}, function(error) {
// doesn't get here either
console.log('error is')
console.log(error)
})
I've found if I console.log the itemsRef itself it will return a largish firebase-y object. I also can log itemsRef.once.toString() and it will log the function signature, but CALLING it doesn't actually work correctly.
I ensured my permissions for the database are read/write as true (boolean). I've ensured that the json for my serviceAccount is correct- I even blew away my firebase project altogether and created a new one.
What gives?

I turned on admin.database.enableLogging(true) and could then see the error message was Googal OAuth token invalid grant error. I created a new service account, no change.
But then I simply changed my local machine (Windows 10) time settings to be automatic time/automatic date. That fixed it!

Related

Firebase admin.auth().createCustomToken(userId) occurred "auth/internal-error: Request contains an invalid argument"

I'm using firebase-admin on a node server
Initializing the admin app works fine:
const admin = require("firebase-admin");
admin.initializeApp({
serviceAccountId: '***.apps.googleusercontent.com'
});
Here's the code I create a custom token and send back to client.
const userId = 'some-uid';
admin.auth().createCustomToken(userId).then((customToken) => {
console.log(customToken);
res.send(customToken);
}).catch((error) => {
console.log(error);
res.status(500).send(error);
});
The error is occurred at line admin.auth().createCustomToken(userId):
code: 'auth/internal-error',
message: 'Request contains an invalid argument.; Please refer to https://firebase.google.com/docs/auth/admin/create-custom-tokens for more details on how to use and troubleshoot this feature. Raw server response: "{"error":{"code":400,"message":"Request contains an invalid argument.","status":"INVALID_ARGUMENT"}}"'
I followed the links below and I don't find any address to solve this
https://firebase.google.com/docs/auth/admin/create-custom-tokens
https://firebase.google.com/docs/auth/admin/errors
I changed the way to initialize the admin, this function works properly.
const admin = require("firebase-admin");
const serviceAccount = require("./serviceAccountKey.json")
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: 'https://<DATABASE_NAME>.firebaseio.com',
serviceAccountId: '***.apps.googleusercontent.com'
});
For more detail please refer to these links:
Generating a custom auth token with a cloud function for firebase using the new 1.0 SDK
https://firebase.google.com/docs/admin/setup
I don't know why it works, cause following this issue https://github.com/firebase/firebase-admin-node/issues/224#issuecomment-390424993, the "creating custom tokens without a service account" feature is implemented. But these changes work for me. Hope it helps!!!

Google storage permissions error while generating signed url from cloud function

I'm attempting to use a Firebase Cloud Function to create signed download URLs for files stored in a Storage Bucket. Using the snippet below on my local machine, I'm able to access cloud storage and generate these URLs.
/* eslint-disable indent */
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
// eslint-disable-next-line #typescript-eslint/no-var-requires
const serviceAccount = require("./test-serviceAccount.json");
admin.initializeApp();
const storage = admin.storage();
const bucket = storage.bucket();
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
}, "firestore");
export const getFile = functions.https.onRequest(async (request, response) => {
const [files] = await bucket.getFiles();
const fileNames: string[] = [];
files.forEach(async (file) => {
console.log(file.name);
const url = await file.getSignedUrl(
{
version: "v2",
action: "read",
expires: Date.now() + 1000 * 60 * 60 * 24,
}
);
fileNames.push(String(url));
if (files.indexOf(file) === files.length - 1) {
response.send(JSON.stringify(fileNames));
}
});
});
However after deploying to Cloud Functions I get an error when I call the function saying:
Error: could not handle the request
and the following message is logged in the functions console:
Error: The caller does not have permission
at Gaxios._request (/workspace/node_modules/gaxios/build/src/gaxios.js:129:23)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at async Compute.requestAsync (/workspace/node_modules/google-auth-library/build/src/auth/oauth2client.js:368:18)
at async GoogleAuth.signBlob (/workspace/node_modules/google-auth-library/build/src/auth/googleauth.js:655:21)
at async sign (/workspace/node_modules/#google-cloud/storage/build/src/signer.js:97:35)
I've tried using and not using a .json service account key and made sure that the service account has permissions (it has Service Account Token Creator, Storage Admin, and Editor roles at the moment).
I also read this issue relating to the python SDK for storage, but it seems to have been resolved. The workaround mentioned in that issue (using a .json service account token) also didn't resolve the permissions errors.
After working with Firebase support - here's what worked for me:
import { initializeApp, applicationDefault } from 'firebase-admin/app';
initializeApp({
credential: applicationDefault(),
projectId: '<FIREBASE_PROJECT_ID>',
});
Specifying the projectId in the init call seems to have resolved the issue.
Signed url means it is signed for (or, accessible to) any particular user for particular span of time, maximum 7 days. If you trying to get it for unauthenticated users, it may show such error(s).
It's better to use getDownloadURL() for unauthenticated users. getSignedUrl() should to used for authenticated users only.

firebase function fails with error gserviceaccount.com:signBlob failed, reason: Client network socket disc

i am trying to create a firebase cloud function which gets download url of an image which is valid for a long time. My code that throws error is as follows:
const admin = require('firebase-admin');
admin.initializeApp();
await admin.storage().bucket('gs://myproject.appspot.com').file(filePath).getSignedUrl({
action: 'read',
expires: '03-09-2491'
})
it looks like my firebase-admin service account does not have permission to create access key. i am not sure how to grant it? as this code works in my local machine when i use a json file to generate the credentials.
any pointers on how to resolve this will be appreciated?
thanks,
Manish
Check the roles assigned to your App Engine default service account ==> [projectID]#appspot.gserviceaccount.com
By default this includes the role of project/editor, you need add the role Cloud Functions Service Agent to the service account, this role includes the permission necessary to generate signed a URL iam.serviceAccounts.signBlob
Please check the permissions/roles of the service account within your bucket, project/editor is enough but if you are using another account you need to assign the role Legacy Bucket Reader
This is a sample code that you can adjust for your use case
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp()
exports.gensigned = functions.https.onRequest(async (req, res) => {
var filePath="myfile.html"
var url = await admin.storage().bucket('gs://myproject').file(filePath).getSignedUrl({
action: 'read',
expires: '03-09-2491'
})
console.log(url)
res.json({ "url": url});
});

Firebase Admin SDK within Firebase Functions CLI - Error fetching access token

I'm trying to use firebase-admin sdk to update my users passwords manually, the idea is to use a onCreate trigger to achieve this by creating a new document in firestore (with the right rules obviously).
According to firebase documentation i don't need to use anything else than this to autenticate from my firebase functions environment:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
In order to test the function i just manually added the document right from the firebase console ui for firestore, and as i can see the trigger is just doing it's work, the problem is when updatin the user password using the firebase-admin sdk.
I'm getting the next error message from the logs:
Error updating user: { Error: 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
this is the whole firebase cloud function if you want to see how it's implemented:
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
triggerNewDocument();
function triggerNewDocument() {
exports.updateUserData = functions.firestore
.document('updateUserPasswords/{userId}')
.onCreate((snap, context) => {
// Get an object representing the document
// e.g. {'name': 'Marie', 'age': 66}
const newValue = snap.data();
console.log(newValue);
// access a particular field as you would any JS property
const uid = newValue.uid;
const newPassword = newValue.password;
return updateUserPassword(uid, newPassword);
// perform desired operations ...
});
}
function updateUserPassword(uid, newPassword) {
admin.auth().updateUser(uid, {
password: newPassword,
})
.then(function(userRecord) {
// See the UserRecord reference doc for the contents of userRecord.
return userRecord.toJSON();
})
.catch(function(error) {
return error;
});
}
Is there anything may i be missing here?, thanks in advance for any hint or help you could provide.
The whole issue was somehow the service account autogenerated with the admin-sdk was inactive.
Anyway i had to disable and enable the service account at least 3 times to make it work, hopefully this can be helpful for anyone having the same issue.
A simple mistake

Firestore (4.10.1): Could not reach Firestore backend. Firestore Access Issues In Cloud Functions

Quick question. Long story short, I am getting this error in my google cloud functions log:
Firestore (4.10.1): Could not reach Firestore backend.
Here is my code in my functions file:
// pull in firebase
const firebase = require('firebase');
// required
require("firebase/firestore");
// initialize firebase
const firebaseApp = firebase.initializeApp({
// Firebase configuration.
apiKey: "<Key Here>",
authDomain: "<Auth Domain>",
databaseURL: "<database url>",
projectId: "<project id>",
storageBucket: "<storage bucket>",
messagingSenderId: "<messaging sender id>"
});
// setup the firestore
var fs = firebaseApp.firestore();
exports.search = functions.https.onRequest((request, response) => {
cors(request, response, () => {
// set a reference to the foo table in firestore
var docRef = fs.collection("foo");
// check for the foo in the firestore
docRef.where('bar', '==', <something>).get().then(function(doc) {
if (!doc.docs) {
return db.collection("foo").add({
bar: <something>
})
.then(function(docRef) {
console.log("Document written with ID: ", docRef.id);
})
.catch(function(error) {
console.error("Error adding document: ", error);
});
}
});
});
});
At this point I am stuck. As far as I can tell, I have things set up, but maybe not? I have searched the docs and googled the issue, without much success. Do you see anything wrong?
All right. So the answer to my question is that I was not being very smart. A big thank you to Taha Azzabi for pointing me in the right direction. It turns out my problem was here:
docRef.where('bar', '==', <something>).get().then(function(doc) {
if (!doc.docs) {
return db.collection("foo").add({
bar: <something>
})
This would never work. My query was correct, but the check on doc.docs was incorrect. My code is now:
// setup the firestore
const fs = firebase.firestore();
// set a reference to the document for the searched summoner
var docRef = fs.collection("bars").doc("snickers");
// check for the bar in the firestore
return docRef.get()
.then(function(doc) {
if (!doc.docs) {
return fs.collection("bars").doc("snickers").set({
name: "snickers"
})
.then(function(reference) {
console.log("Document written");
return response.status(200).send('');
})
This is what I was looking for so I am good to go. Long story short, I was grabbing a collection of results then trying to check to see if a single result existed. What I needed to do was grab a single doc from the firestore and from there check to see if the single doc existed. However, the error:
Firestore (4.10.1): Could not reach Firestore backend.
Didn't really do a very good job at pointing me in that direction.
Did you install the Firebase CLI ?
npm install -g firebase-tools
Did you log in to the Firebase console through the CLI ?
firebase login
Did you initialize Firebase Cloud Functions ?
firebase init functions
You don't need then to reinitialize the app, initialize an admin app instance,thought.
Here's an example hope that will help
const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase)
//trigger a function to fire when new user document created
exports.createUser = functions.firestore
.document('users/{userId}')
.onCreate(event => {
// perform desired operations ...
});
to deployer your functions
firebase deploy --only functions
read more here https://firebase.google.com/docs/functions/get-started

Resources