Skip to content

PERMISSION_DENIED when using Firebase Admin SDK and Firestore Emulator #2310

@sgr-ksmt

Description

@sgr-ksmt

Summary

[REQUIRED] Environment info

  • firebase-tools: 8.4.1
  • firebase-admin: 8.12.1
  • firebase-functions: 3.6.1
  • (@firebase/testing: ^0.19.6)
  • node: v10.17.0

Platform:
macOS

[REQUIRED] Test case

I have a minimal Cloud Functions code and firestore.rules:

import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'

admin.initializeApp()

export const userCreated = functions.firestore.document('users/{userID}').onCreate(async (snapshot, context) => {
  const userRef = admin.firestore().collection('users').doc(context.params.userID)
  const user = await userRef.get()
  console.log(`user: ${user.data()}`)
  await userRef.update({ age: 30 })
  return undefined
})
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
  }
}

In the function, I call admin.firestore().collection(...).doc(...).get() to get/update a user document from DB.
In the rules, I restrict all operations. But admin SDK can operate without the influence of firestore.rules

I setup emulators and ran firebase emulators:start --only functions,firestore, then I ran test:

import 'jest'
import * as firebase from '@firebase/testing'

// Please input your firebase project id.
const REAL_FIREBASE_PROJECT_ID = 'your-firebase-project-id'

describe('test user.onCreate', () => {
  let unsubscribe: any
  afterAll(() => {
    firebase.clearFirestoreData({ projectId: REAL_FIREBASE_PROJECT_ID })
    if (unsubscribe) {
      unsubscribe()
    }
  })
  describe('created company', () => {
    test('primary company should be set in user', async done => {
      const db = firebase
        .initializeAdminApp({ projectId: REAL_FIREBASE_PROJECT_ID })
        .firestore()

      const userRef = db.collection('users').doc('bob')
      await userRef.set({ name: 'bob' })

      unsubscribe = userRef.onSnapshot(snap => {
        console.log(snap.data())
        if (snap.data() && snap.data()!.age === 30) {
          done()
        }
      })
    })
  })
})

Finally, I got error:

i  functions: Beginning execution of "userCreated"
⚠  functions: Error: 7 PERMISSION_DENIED: 
false for 'get' @ L5
    at Object.callErrorFromStatus (/Users/foobar/src/github.com/user/plane-emulator-sandbox/functions/node_modules/@grpc/grpc-js/build/src/call.js:30:26)
    at Object.onReceiveStatus (/Users/foobar/src/github.com/user/plane-emulator-sandbox/functions/node_modules/@grpc/grpc-js/build/src/client.js:328:49)
    at Object.onReceiveStatus (/Users/foobar/src/github.com/user/plane-emulator-sandbox/functions/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:304:181)
    at Http2CallStream.outputStatus (/Users/foobar/src/github.com/user/plane-emulator-sandbox/functions/node_modules/@grpc/grpc-js/build/src/call-stream.js:116:74)
    at Http2CallStream.maybeOutputStatus (/Users/foobar/src/github.com/user/plane-emulator-sandbox/functions/node_modules/@grpc/grpc-js/build/src/call-stream.js:155:22)
    at Http2CallStream.endCall (/Users/foobar/src/github.com/user/plane-emulator-sandbox/functions/node_modules/@grpc/grpc-js/build/src/call-stream.js:141:18)
    at Http2CallStream.handleTrailers (/Users/foobar/src/github.com/user/plane-emulator-sandbox/functions/node_modules/@grpc/grpc-js/build/src/call-stream.js:266:14)
    at ClientHttp2Stream.stream.on (/Users/foobar/src/github.com/user/plane-emulator-sandbox/functions/node_modules/@grpc/grpc-js/build/src/call-stream.js:315:26)
    at emitThree (events.js:136:13)
    at ClientHttp2Stream.emit (events.js:217:7)
Caused by: Error
    at Firestore.getAll (/Users/foobar/src/github.com/user/plane-emulator-sandbox/functions/node_modules/@google-cloud/firestore/build/src/index.js:687:23)
    at DocumentReference.get (/Users/foobar/src/github.com/user/plane-emulator-sandbox/functions/node_modules/@google-cloud/firestore/build/src/reference.js:199:32)
    at exports.userCreated.functions.firestore.document.onCreate (/Users/foobar/src/github.com/user/plane-emulator-sandbox/functions/lib/index.js:9:32)
    at cloudFunction (/Users/foobar/src/github.com/user/plane-emulator-sandbox/functions/node_modules/firebase-functions/lib/cloud-functions.js:132:23)
    at runFunction (/Users/foobar/src/github.com/user/plane-emulator-sandbox/functions/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:553:20)
    at /Users/foobar/src/github.com/user/plane-emulator-sandbox/functions/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:538:19
    at Generator.next (<anonymous>)
    at /Users/foobar/src/github.com/user/plane-emulator-sandbox/functions/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:8:71
    at new Promise (<anonymous>)
    at __awaiter (/Users/foobar/src/github.com/user/plane-emulator-sandbox/functions/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:4:12)
⚠  Your function was killed because it raised an unhandled error.

But this function worked perfectly when I deployed it to Firebase.

I think admin.firestore() is usually NOT affected by firestore.ruels.
But actually it was affected by firestore.rules while running firestore, functions emulator.

btw, if yarn.lock is updated as follows, it will work while running emulators:

sgr-ksmt/plain-emulator-sandbox#1

It's so confusing..

Maybe it's because of some of dependencies, but I don't know why it works when I change yarn.lock.

[REQUIRED] Steps to reproduce

I prepared sample project here: https://github.com/sgr-ksmt/plain-emulator-sandbox

This sample was made from scratch(created a new repository, ran firebase init, install latest dependencies).

git clone path/to/project
cd functions/
yarn
yarn test

[REQUIRED] Expected behavior

admin.firestore().collection(...).doc(...).get() will be successful and should not be affected by firestore.rules

[REQUIRED] Actual behavior

admin.firestore().collection(...).doc(...).get() was failed due to permission denied. It was affected by firestore.rules

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions