CONTEXT
Data schema:
users collection
- This collection holds authenticated user documents (document ID equals auth.uid).
- It does not store organization or member profile references.
member_profiles collection
- Contains a user_ref field (a document reference to the users collection).
- Contains an organization_ref field (a document reference to the organization collection).
- Document IDs here do not correspond to users as not all created members log in and one user can have multiple member profiles.
tasks collection
- Contains an organization_ref field (a document reference to the organization collection)
EXPECTED BEHAVIOR
Allow read, create, write, and delete operations on tasks if the logged-in user belongs to the organization associated with the task. The organization is determined via the member profile(s) attached to the user.
CURRENT ISSUE
I tried using Firestore rules that attempt to retrieve the user’s member profile with a query using .where
as shown below, but it doesn’t work (an error is thrown). I understand that get()
must refer to a fixed document path, yet I can’t determine how to construct the path dynamically based on the logged-in user. What is the correct Firestore rule logic or function?
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Helper function to get user's member profile
function getUserMemberProfile() {
return get(/databases/$(database)/documents/member_profiles)
.where('user_ref', '==', /databases/$(database)/documents/users/$(request.auth.uid))
.first();
}
// Check if user and resource belong to the same organization using document references
function isSameOrg(resourceOrgRef) {
let profile = getUserMemberProfile();
return profile != null && profile.data.organization_ref == resourceOrgRef;
}
// Tasks collection rules
match /tasks/{document} {
allow read: if request.auth != null && isSameOrg(request.resource.data.org_ref);
allow write: if request.auth != null && isSameOrg(request.resource.data.org_ref);
}
}
}
ATTEMPTED ALTERNATIVE
Based on comments, I added a list of organization references to the user document to align with the user’s multiple member profiles, but this function still results in an 'unknown error'. See supporting documentation: https://firebase.google.com/docs/reference/rules/rules.List
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Check if user and resource belong to the same organization using document references
function isUserInOrg(taskOrgRef) {
let userDoc = get(/databases/$(database)/documents/users/$(request.auth.uid));
return userDoc.exists() && taskOrgRef in userDoc.data.organization_ref;
}
// THIS DOES NOT WORK WHEN CHECKING IF TASK ORG (type: document reference) IS IN USER'S LIST OF ORGS (type list of doc ref)
match /tasks/{document} {
allow create, write: if request.auth != null && isUserInOrg(resource.data.org_ref);
allow read: if true;
allow delete: if request.auth != null && isUserInOrg(resource.data.org_ref);
}
// THIS WORKS FINE FOR AUTHENTICATED USERS
// match /tasks/{document} {
// allow create: if request.auth != null;
// allow read: if true;
// allow write: if request.auth != null;
// allow delete: if request.auth != null;
// }
}
}
Please advise on the correct approach or necessary changes to meet Firestore rules constraints and achieve the desired behavior.