I'm trying to setup role based authentication in Cloud Firestore. The intent is to have it set up so that only users within an organization can read the organization or associated events. It is working when the client requests a single document (get), but not a query of documents (list).
My collection called organizations looks like this, so far only containing a single document with ID devtest:
{
"name": "Dev Test"
"users": [
"STFg0EvGemTaD2r9jyby0UMSt6O2"
]
"orgid": "devtest"
}
I also have a collection of events (so far also only containing one):
{
"name": "foo",
"orgid": "devtest",
...
}
And my rules look like this:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function isSignedIn() {
return request.auth != null;
}
function userIsUser() {
return isSignedIn() &&
request.auth.uid in get(/databases/$(database)/documents/organizations/$(resource.data.orgid)).data.users;
}
match /organizations/{org} {
allow read: if userIsUser();
allow write: if false;
}
match /events/{event} {
allow read: if userIsUser();
allow write: if userIsUser();
}
}
}
What I'm confused about is why I can do a get and it succeeds, for example:
firebase.firestore().collection('organizations').doc('devtest').get()
but when I try a query it fails, for example:
firebase.firestore().collection('organizations').where('users', 'array-contains', firebase.auth().currentUser ? firebase.auth().currentUser.uid : false)
responds with permission denied. I know that a security rule is not a filter, there is only the one document in the collection right now.
Any suggestions on what I might be missing?
Thanks!
According to this documentation, using authentication objects directly causes issues, since they can be in an intermediary state. It’s recommended you also create an authentication listener that waits for the state to change.
By using an observer, you ensure that the Auth object isn't in an intermediate state—such as initialization—when you get the current user. When you use signInWithRedirect, the onAuthStateChanged observer waits until getRedirectResult resolves before triggering.
If this is happening in your query, it might explain why it gives you the permissions error, as the object can be still initializing and resolving to false instead of true.