firebase-functions: Permission denied on set value

I am simply doing this: admin.database().ref(/chat/last_message/${currentUserId}).set(currentTimestamp);

however I get:

FIREBASE WARNING: set at /chat/last_message/46wyOyreyYSocywqEt1g3943OAH2 failed: permission_denied

even though my database rule is only:

"chat": {
      "last_message": {
        "$uid": {
          ".write": true
        }
      },
}

Strange thing is I do the exact thing on my other firebase account, and it worked perfectly fine.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 21 (1 by maintainers)

Most upvoted comments

Hey @azraelx23, I’m starting to get lost in all the different directions this is heading. Let me give you some general tips about how things are supposed to work and then maybe you can help put together a clear repro of the issue for me.

The event.data available as part of a Database Cloud Function is an instance of DeltaSnapshot. That DeltaSnapshot has both a ref property and an adminRef property. The ref property has the same access to the Realtime Database as the client that triggered the Cloud Function. So, if an unauthenticated client triggered the Cloud Function, then ref would likewise be unauthenticated. If instead an authenticated client triggered the Cloud Function, then ref would likewise be authenticated as that client. The adminRef property has full read and write access to the Realtime Database and should (in theory) never see a permission_denied error.

In your initial post, you are using admin.database().ref(), but instead should probably be using event.data.adminRef which is already authenticated for you. In your last post, you are using event.data.ref which may just be failing because your Security Rules are indeed blocking the write.

In order for me to help you, I’ll need to see an mcve of your problem. This would include the full contents of you index.js and the Security Rules you are using for the relevant nodes. Ideally, you’d be able to get rid of any extraneous code that isn’t part of the repro.

Hope that helps.

Thanks @jwngr and firebase team! Great team effort!

Mystery solved! After a bunch of back and forth, we finally tracked down the underlying problem. Cloud Functions use your Firebase project’s App Engine default service account to authenticate adminRef. This service account is created automatically when your project is created and by default has an IAM permission of Editor. You can see what permission it has by looking here. In this case, the App Engine default service account has somehow gotten set to an IAM role of Viewer, which only granted it read access to the Realtime Database, not write access. The fix was simply to make it an Editor once again.

Thanks to @azraelx23 for helping to debug this and being patient while we tracked it down!

@ahaverty sorry please ignore the very first post and check my latest sample code, it is a database trigger and it has transaction right on this line

return countRef.transaction((current) => {
    if (event.data.exists() && !event.data.previous.exists()) {
      return (current || 0) + 1;
    } else if (!event.data.exists() && event.data.previous.exists()) {
      return (current || 0) - 1;
    }
    return (current || 0);
  });