Search code examples
google-cloud-firestorefirebase-security

Why does firestore throw permission denied if the security rule parameter is not part of the query?


I know for every doc in my collection that request.auth.uid is in request.resource.data.users if request.resource.data.foo === bar

// security rule
match /collection/{id}/{document=**} {
   allow read: if request.auth.uid in request.resource.data.users;
}

// does not work
const snapshot = await collectionRef.where("foo", "==", "bar").get()

// works
const snapshot = await collectionRef.where("foo", "==", "bar").where("users", "array-contains", userID).get()

Even though every doc in the collection satisfies the security rule firestore throws permission denied. Once I add the additional users query parameter clause the query works.


Solution

  • Security rules that involve field filters on a query do not examine the actual contents of the documents. That would not scale at all for massive collections. Every query in Firestore must be able to scale massively.

    What security rules do is check to see that the query does not request anything that is not explicitly allowed by the rules. Your rule is effectively saying "do not allow anyone to make a query on collection unless there is an array-contains filter on the field uid where they provide their actual uid as verified by Firebase Auth".

    Your first query does not specify that required filter, so it is immediately reject. Your second query does specify that required filter, so it passes. Again, the contents of any documents don't matter at all.

    I suggest also reading this part of the documentation carefully.