Order of execution in Firestore query pipeline - why missing permissions?
My Firestore collection contains one document per user, and the user ID is the ID of the document.
I have the following rules:
match /mycollection/{userId} {
allow read, update, delete: if userId == request.auth.token.email;
allow create, update: if request.auth.uid != null && userId == request.auth.token.email;
}
This guarantees that
- every user can read, update and delete "their" document,
- a new user can create "their" document.
This works great when I load the user's document "by ID".
However, it does not work when the document is loaded via a query:
const query = db.collection("mycollection")
.where("user", "==", userId)
.where("writeDate", ">", writeDate)
.get()
As you can see, the user only loads "their own document", so in my opinion, the request satisfies the access rules. However, I get a "Missing or insufficient permissions" error anyway.
Why?
I suppose this has to do with the execution order of queries and rules on Firestore, but I have not found anything in the documentation about this. As long as I only access the documents I have the right to read, everything should be fine, no?
In case you are wondering: I need the query to download the document only if it has changed (hence the "date" where clause). I know I can do that with realtime updates (using onSnapshot
or similar). I do not want to know alternative approaches.
Solution 1:
Found it. The following rules do not work:
match /mycollection/{userId} {
allow read, update, delete: if userId == request.auth.token.email;
allow create, update: ...
}
These rules do work:
match /mycollection/{userId} {
allow read, update, delete: if resource.data.user == request.auth.token.email;
allow create, update: ...
}
The userId
works only if the document is accesssed via its ID.
If the rule is based on a field of the document (here: user
), it needs to use the field as resource.data.user
.