I've been working on integrating a Firebase Cloud Function to update a document in my Firestore database whenever another document is updated. The trigger is functioning correctly, but I'm encountering an error when trying to access the other document using the firebase admin instance for updating.
Error: 7 PERMISSION_DENIED: Missing or insufficient permissions.
at Object.exports.createStatusError (/user_code/node_modules/firebase-admin/node_modules/grpc/src/common.js:87:15)
at ClientReadableStream._emitStatusIfDone (/user_code/node_modules/firebase-admin/node_modules/grpc/src/client.js:235:26)
at ClientReadableStream._receiveStatus (/user_code/node_modules/firebase-admin/node_modules/grpc/src/client.js:213:8)
at Object.onReceiveStatus (/user_code/node_modules/firebase-admin/node_modules/grpc/src/client_interceptors.js:1256:15)
at InterceptingListener._callNext (/user_code/node_modules/firebase-admin/node_modules/grpc/src/client_interceptors.js:564:42)
at InterceptingListener.onReceiveStatus (/user_code/node_modules/firebase-admin/node_modules/grpc/src/client_interceptors.js:614:8)
at /user_code/node_modules/firebase-admin/node_modules/grpc/src/client_interceptors.js:1019:24
Function code:
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
admin.initializeApp();
const settings = { timestampsInSnapshots: true };
admin.firestore().settings(settings);
export const onDocUpdate = functions.firestore
.document("documents/{documentId}")
.onUpdate((snapshot, context) => {
console.log("onDocUpdate called ", context.params.documentId);
const document = snapshot.after.data();
console.log("Document: ", document);
if (document.screw) {
console.log("Document screw exists. ", document.screw);
const docRef = admin
.firestore()
.collection("screws")
.doc(document.screw);
return docRef
.get()
.then(doc => {
if (doc.exists) {
console.log("Screw for document exists.");
} else {
console.error(
"Screw for document not found! ",
document.screw
);
}
})
.catch(error => {
// Here I get the permission error :(
console.error(
"Screw for document doc load error!! ",
error
);
});
} else {
console.error("Document is not bound to a screw! ", document.id);
}
return null;
});
package.json
{
"name": "functions",
"scripts": {
"lint": "tslint --project tsconfig.json",
"build": "tsc",
"serve": "npm run build && firebase serve --only functions",
"shell": "npm run build && firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"main": "lib/index.js",
"dependencies": {
"@google-cloud/firestore": "^0.16.0",
"firebase-admin": "^6.0.0",
"firebase-functions": "^2.0.4",
"protobufjs": "^6.8.8"
},
"devDependencies": {
"tslint": "~5.8.0",
"typescript": "~2.8.3"
},
"private": true
}
I suspect that the issue may be related to permissions of the admin instance, but I'm unsure about what could be causing this error. I have followed the documentation and tutorials provided by Firebase without success.
Although my account is still on a Free Plan, I am receiving a notification in the logs suggesting that I configure a billing account. However, according to the documentation, I should be able to access Google Cloud Platform services and read nodes within the same database without any issues.
I have come across similar issues on Stack Overflow but have not yet found a solution. Perhaps someone else has encountered and resolved this issue since then?
PERMISSION_DENIED Firestore CloudFunction TypeScript and Firebase error writing to Firestore via a Function: "7 PERMISSION_DENIED: Missing or insufficient permissions"
Update 1: I had another problem with the new timestampsInSnapshots setting, which has been resolved and the code above has been updated. However, the main issue of permission denied still persists.
Update 2: In response to the answer given by @RonRoyston below, this is a Cloud Function utilizing the Admin SDK from the firebase-admin package to access the node. Thus, it should not be affected by Firestore security rules. There is already a comment on one of the linked questions by @DougStevenson highlighting this. Based on the Admin SDK documentation, initializing it by calling admin.initializeApp() should suffice, but unfortunately, it does not seem to work in my case. I have not come across any information stating the need for special IAM settings within service accounts or security rules when using Cloud Functions, so I have not made any adjustments to these settings.
Cheers, Lars