Search code examples
javascriptfirebasegoogle-cloud-firestorefirebase-security

Firebase rules passing in simulation but not on same operation in front-end


I have a firestore rule for a collection "orders" and i use the simulator tool to est my rules and they definitely pass for all reads, yet when i attempt to display the orders in my console i get an error

Rules

match /orders/{document=**} {
      allow read;
      allow write: if isAdmin();
      allow create: if isOrderOwner();
    }

function isAdmin() {
  return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.userinfo.isAdmin;
}

function isOrderOwner() {
    return get(/databases/$(database)/documents/orders/$(request.auth.uid)) == request.auth.uid
}

On my app, all i'm doing is console.log(orders) and i get this error:

Uncaught Error in snapshot listener: FirebaseError: Missing or insufficient permissions.

In my front end (react)

db.collectionGroup('orders').onSnapshot(snap => {
  let ordersArr = []  
  snap.forEach(doc => { 
    if(doc.data().orderid) 
      ordersArr.push(doc.data())
  })  
  setAllOrders(ordersArr)   
  console.log(ordersArr) // ->  this console causes the insufficient permissions error      
})

I can't figure it out, i very simply have allow read; for all documents in my orders collection.

Note: the orders are in a subcollection of the orders collection (i don' think that is the problem though)


Solution

  • You are using collectionGroup so if I assume orders is a sub-collection for each document in parent collection, let's say users or customers, the rules should ideally be something like this:

    rules_version = '2';
    service cloud.firestore {
      match /{path=**}/orders/{orderId} {
          allow read;
          allow write: if false; // <- any rules you have for writes
      }
    }
    

    I ran the following query and the read operation was allowed:

    const snapshot = await firebase.firestore().collectionGroup("orders").get();
    console.log(snapshot.size, "docs")
    

    The {path=**} is a recursive wildcard as mentioned in the documentation.

    The documentation says,

    In your security rules, you must explicitly allow collection group queries by writing a rule for the collection group:

    1. Make sure rules_version = '2'; is the first line of your ruleset. Collection group queries require the new recursive wildcard {name=**} behavior of security rules version 2.

    2. Write a rule for you collection group using match /{path=**}/[COLLECTION_ID]/{doc}.