I’m using Firestore do store my data with this Firebase Service.
I’ve set this Security Rule where the user only can access a document if his auth UID is into an array, which is inside a base document that he is going to fetch.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /mock_text/{document}/{path=**} {
allow read, write: if
request.auth.uid in get("/databases/$(database)/documents/mock_text/$(document)/").data.userSessions;
}
}
}
The userSessions list is changed by my back-end server, so don’t worry about that. I have already ensured it works.
When I try to do this request in my Flutter app (I am authenticated anonymously), I get this error with this query:
final query = _firestore
.collection("mock_text")
.where("userSessions", arrayContains: currentUser!.uid);
Error:
FirebaseException ([cloud_firestore/permission-denied] The caller does not have permission to execute the specified operation.)
I already assured that the connection with Firestore and Auth is working, because if I change the rules to request.auth.uid != null, it works, so that is not the problem.
What can I do to it work correctly?
I’m assuming something is wrong with the query made in Flutter, because while testing with Firestore Security Rules playground it worked. Any ideas?
2
Answers
Firestore security rules don’t filter data. Instead they merely ensure that your code follows the rules that you’ve set for data access. It needs to do that without actually having to inspect every piece of data, as performance would never scale otherwise.
Your rules try to load a specific document, and while that seems to be the same document that is actually being considered, it seems like the rules engine can’t validate that for a
list
type call.Luckily, I don’t think you need to
get()
the document here, as the data you need is available already in theresource.data
variable:Don’t use quotes around the path you pass to
get()
. You can see examples of how it’s supposed to work in the documentation. What you need to pass is a Path object to get(), not a string.