Security

NoSQL Schema

Recommended schema is having the userId somewhere in the file path, and updating the Security Rules like so:

// Grants a user access to a node matching their user ID
service firebase.storage {
match /b/{bucket}/o {
// Files look like: "user/<UID>/path/to/file.txt"
match /user/{userId}/{allPaths=**} {
allow read, write: if request.auth.uid == userId;
}
}
}

Sub-collections

If you use something like {allPaths=**}, this also includes subcollections. If you have set up conditionals based on the response object, you will need to ensure that the condition exists at every level. For example:

// Grants a user access to a node matching their user ID
service firebase.firestore {
match /document/{database}/tables {
match /user/{userId}/{allPaths=**} {
allow read, write: if response.data.role == "ADMIN";
}
}
}

This will expect even subcollections that matched with {allPaths=**} to have a field role. In order to get around this you want to set a full path:

// Grants a user access to a node matching their user ID
service firebase.firestore {
match /document/{database}/tables {
match /user/{userId}/{allPaths=**} {
allow read, write: if get(/document/$(database)/tables/user/$(request.auth.uid)).data.role == "ADMIN";
}
}
}

https://medium.com/@khreniak/cloud-firestore-security-rules-basics-fac6b6bea18e