I'd like to query a Firestore collection based on a string field, returning all documents where that field starts with a custom claim on the user's auth token. I was able to use this answer to create a query using >=
and <
operators with a successor key, and this works well for me when my I relax my Firestore rules.
I'd like to lock down my ruleset so that a user only has access to documents that start with their custom claim.
I've read the rules are not filters literature, and from my understanding of it, I just need to write rules such that my query can never return data that would violate the rules.
So that's what I'm attempting to do without much success:
I have a Firestore collection with documents that look something like this:
{
"id": 1,
"namespace": "foo.bar"
}
Each user has a custom claim on their auth token, let's say it's my_namespace
.
I wrote a Firestore rule like so:
function hasNamespaceAccess(request, resource){
//allow if data.namespace starts with request.token.my_namespace
return resource.data.namespace.matches(request.auth.token.my_namespace + ".*");
}
match /path_to_my_objects/my_collection/{my_obj} {
allow read, write: if hasNamespaceAccess(request, resource);
}
My query, after simplifying to make this post as concise as I can, looks like this:
return db
.collection('my_collection')
.where('namespace', '>=', 'foo.') //the namespace "query values" are hard coded for clarity here
.where('namespace', '<', 'foo.c')
The token which is used when making a call to Firestore does, for sure, have "my_namespace": "foo"
What I Expect
My Firestore rules says that a user has access to any document where namespace
starts with "foo" -- the doc with "namespace": "foo.bar"
conforms to this.
My query should only return documents where namespace is between "foo." and "foo.c". Again, my document conforms to this. This query, I believe, can never return a document that does not conform to the regex string in my Firestore rule.
As such, I'd expect to get a result set with my document.
What actually happens
index.cjs.js:13448 Uncaught Error in snapshot listener: FirebaseError: Missing or insufficient permissions. at new n (index.cjs.js:129) at index.cjs.js:10175 at index.cjs.js:10176 at n.onMessage (index.cjs.js:10209) at index.cjs.js:10115 at index.cjs.js:10146 at index.cjs.js:5542
I've tried modifying my query to not use a range, and to only have where("namespace", "==" "foo.bar")
, and this works as expected, so it seems like the rest of the system is working fine, but there is a mismatch between the rules and the filter clause.