I have these rules:
match /suuntoAppAccessTokens/{userName} {
allow create: if request.auth.uid != null && request.auth.token.firebase.sign_in_provider != 'anonymous';
match /tokens/{userID} {
allow read, write, create, update, delete: if request.auth.uid == userID && request.auth.token.firebase.sign_in_provider != 'anonymous';
}
}
match /{path=**}/tokens/{userID} {
allow read, write, create, update, delete: if request.auth.uid == userID;
}
That means that for the path /suuntoAppAccessTokens/dimitrioskanellopoulos/tokens/{userID}
the current user should have access.
However, when I query the collection group like so:
return this.afs.collectionGroup('tokens').snapshotChanges();
I get a permission error.
Getting directly the document under tokes/{userID} works as expected.
What can I do so that the current user can run a collectionGroup query and get the items he is permitted to get based on my rules?
Your rule is expecting that the security rule will filter all the documents from all of the tokens
collection so that only the current user's documents will be read. This is not possible with security rules. Security rules are not filters. From the documentation:
When writing queries to retrieve documents, keep in mind that security rules are not filters—queries are all or nothing. To save you time and resources, Cloud Firestore evaluates a query against its potential result set instead of the actual field values for all of your documents. If a query could potentially return documents that the client does not have permission to read, the entire request fails.
You will need to change your query so that the client is only requesting documents that are fully expected to be readable by the current user. Unfortunately, it's not possible for me tell if this is possible with your current schema. The ID of the document {userId} can't be used in a collection group query to filter the documents. So, you must ensure that both of the following criteria are met:
I suggest storing the uid of the user in the document with the token, the same as {userId} in the rule. You can query it like this:
collectionGroup('tokens').where("uid", "==", uid)
Be sure that the client passes in the uid
correctly.
Also, you will need to make sure that the rule is granting access by the exact same criteria:
match /{path=**}/tokens/{userID} {
allow read, write, create, update, delete:
if request.auth.uid == resource.data.uid;
}
This will only allow access to the document if its uid
field is the same as the auth uid
, which is exactly what the client is asking for.