3
votes

I'm trying to write a simple Firebase Function that adds a record to Firestore with TypeScript. The cut down version of the code is:

import * as admin from "firebase-admin";
import * as functions from "firebase-functions";

const config = functions.config();

admin.initializeApp(functions.config().firebase);
admin.database.enableLogging(true);

exports.subscriptions = functions.https.onRequest(
  async (req, res) => {
    try {
      const requestSubscription = req.body;
      const subscription = {
        subscription_id: requestSubscription.subscription_id,
        email: requestSubscription.email || ""
      };

      const id = subscription.subscription_id;
      const dbSubscriptions = admin.firestore().collection("subscriptions");
      await dbSubscriptions.doc(id).set(subscription);

      return res.status(200).send(`Success`);
    } catch (e) {
      console.error(e.stack);
      return res.status(500).send(`Error`);
    }
  }
);

This works as expected locally. When I deploy, I get this error:

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 Object.onReceiveStatus (/user_code/node_modules/firebase-admin/node_modules/grpc/src/client_interceptors.js:1214:28)
    at InterceptingListener._callNext (/user_code/node_modules/firebase-admin/node_modules/grpc/src/client_interceptors.js:590:42)
    at InterceptingListener.onReceiveStatus (/user_code/node_modules/firebase-admin/node_modules/grpc/src/client_interceptors.js:640:8)
    at callback (/user_code/node_modules/firebase-admin/node_modules/grpc/src/client_interceptors.js:867:24)

My functions/package.json file is:

{
  "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": {
    "express": "4.16.3",
    "firebase-admin": "5.12.1",
    "firebase-functions": "1.0.3"
  },
  "devDependencies": {
    "tslint": "^5.8.0",
    "typescript": "^2.5.3"
  },
  "private": true
}

The only link I'm getting searching for this error is this unanswered question: PERMISSION_DENIED Firestore CloudFunction TypeScript

I've set my Firestore rules to allow anyone to read and write as well even though the above is using admin and it still doesn't work.

Can anyone help?

3
functions.config().firebase is obsolete since version 1.0 of firebase-functions. You should just init with no arguments now. Also you should import firebase-functions before firebase-admin. Don't know if these will fix anything, but please try. Also update all your npm dependencies and note the versions in your question.Doug Stevenson
@DougStevenson Thanks for the quick reply. I've added my package.json to the question. Using "firebase-admin": "5.12.1", "firebase-functions": "1.0.3". I tried removing the arguments and swapping the imports but there was no difference.fstr
@DougStevenson: So I'm finding it I use "admin.initializeApp" while supplying the privateKey, databaseURL, clientEmail and projectId it works remotely. I'm really stumped at why the recommended way isn't working. Have I missed some server setup step? I've no idea what to try next.fstr
Try reporting this to Firebase support. firebase.google.com/support/contact/troubleshootingDoug Stevenson

3 Answers

2
votes

I contacted Firebase support about this and they didn't know what was going on either. I created a new project, deployed and it worked. Perhaps it's just a weird glitch with new projects.

2
votes

I encountered this issue while updating my IAM/Service account value and I think I figured it out.

If you use Firebase Admin SDK without providing any credentials in Firebase Functions like this firebaseAdmin.initializeApp() then your functions will use default application credentials.

The default credentials uses the following service account {project-id}@appspot.gserviceaccount.com where {project-id} will be your firebase/google cloud project id. This account is often created automatically when you created Firebase project or used few of google cloud services.

Anyhow, {project-id}@appspot.gserviceaccount.com by default has Editor level permission. You can check this out in [Google Cloud - IAM & Admin - IAM] page. I thought it had too much permissions so I basically removed that permission from the service account, and decided to manually add more restrictive permissions. (At that time, I did not know that firebase/cloud functions use this service account.

After making those changes, my functions which access Firestore soon started encountering Error: 7 PERMISSION_DENIED: Missing or insufficient permissions. errors. In order to solve this issue, I had to do the following 2 things.

  • Added back Editor level permission back to the default service account.
  • Deleted Firestore functions completely using Firebase console, and re-deployed them using firebase deploy --only functions command.

After completing above 2 steps, my cloud functions started working correctly as expected.

0
votes

My project was created at google cloud first, then connecting that project to firebase.

In my case the issue was {project-id}@appspot.gserviceaccount.com didn't had Editor role, as soon as I added Editor roles for that service account, it started working

p.s Also for the first time, the user should be Owner to be able to create firestore database, otherwise you see this message in firestore page To manage Cloud Firestore, ask a project owner for the necessary permissions