In my database, I have a collection containing documents from various users. Each document has a user
property with the user’s email as its value. (I’m going to change that to userID later on.)
I want to make sure that a user can only read, update and delete documents where the user’s email (request.auth.token.email) matches the value of the user
property.
I spent several hours trying to find a solution. I think this is my best approach, but it doesn’t work:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if isSignedIn() && emailVerified();
}
match /fooCollection/{document} {
allow create: if isSignedIn() && emailVerified() && userValueIsNotManipulated();
allow update, delete: if isSignedIn() && emailVerified() && isOwner() && userValueIsNotManipulated();
allow read: if isSignedIn() && emailVerified() && isOwner();
}
/// Functions ///
function isSignedIn() {
return request.auth != null
}
function emailVerified() {
return request.auth.token.email_verified
}
function isOwner() {
return request.auth.token.email == resource.data.user
}
function userValueIsNotManipulated() {
return request.resource.data.user == request.auth.token.email
}
}
}
I also tried:
match /fooCollection/{user}
match /fooCollection/{user} {
...
...
allow read: if isSignedIn() && emailVerified() && request.auth.token.email == user;
}
match /fooCollection/{user}/{document=**}
match /fooCollection/{document}/{user}
I have a second collection with a similar data structure. In the current state of my project, I make a request to firestore to get the fooCollection. Then, I filter it locally for the user’s documents. The request for the second collection works in the same way. I, therefore, expected my request for the first collection to fail with the above securety rules, and the request for the second collection to largely work. In my attempts so far, either both requests were successful, or both requests failed.
So, how can I make sure, that a user can only read, update and delete documents where the user’s email (request.auth.token.email) equals the value of the property user
?
2
Answers
Thanks @Bjorn Ironside!
Here is my solution:
Now it works as expected. When my app tries to access the fooCollection I get the FirebaseError: Missing or insufficient permissions.
Only logged in and authenticated users can access the secondCollection. In the fooCollection you can only access your own documents. Apart from that, no access is possible.
Security rules allow for overlapping rules.
"It’s possible for a document to match more than one match statement. In the case where multiple allow expressions match a request, the access is allowed if any of the conditions is true"
It looks like this statement will allow any read or write and that will override the second match statement.
Since both match statements use this same condition, it will always be true or always be false on all.