javascriptfirebasegoogle-cloud-firestoregoogle-cloud-datastorefirebase-security

Firestore Security Rules: (minimal) code that doesn't work against these rules


I'm working on setting up Firestore security rules, but I'm facing an issue where my custom function getUserOrganization() doesn't seem to return the correct value when used in matching conditions. Specifically, the function is supposed to return the organization ID of the authenticated user, but the matching condition doesn't seem to work as expected.

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
  
    match /Users/{userId} {
      allow read, write: if request.auth.uid == userId;
    }
    
    match /Organisations/{orgId} {
      allow read, write: if request.auth != null && getUserOrganization() == orgId;
      
      match /{subcollection=**}/{docId} {
        allow read, write: if request.auth != null && getUserOrganization() == orgId;
      }
    }
  }

  // Function to get the user's organization from their document
  function getUserOrganization() {
    return get(/databases/$(database)/documents/Users/$(request.auth.uid)).data.organisation.id;
  }
}

Issue

When I try to access an organization document using the rule:

allow read, write: if request.auth != null && getUserOrganization() == orgId;

It throws a permission error. However, if I hardcode the organization ID like this:

allow read, write: if request.auth != null && "Sjc7mG12B0LPPe5bcJOf" == orgId;

The rule works as expected, and access is granted.

This leads me to believe that the getUserOrganization() function might not be returning the correct value or might be returning a value in a different format (e.g., different data type, string encoding, etc.).

What I've Tried:

Additional Information:

Any insights or suggestions on how to fix this issue would be greatly appreciated.


Solution

  • From what I understand or from my past experience with Firebase security rules, I think they shouldn't return anything other than boolean values.

    So, can you try doing this instead:

    rules_version = '2';
    
    service cloud.firestore {
      match /databases/{database}/documents {
      
        match /Users/{userId} {
          allow read, write: if request.auth.uid == userId;
        }
        
        match /Organisations/{orgId} {
          allow read, write: if request.auth != null && getUserOrganization(orgId);
          
          match /{subcollection=**}/{docId} {
            allow read, write: if request.auth != null && getUserOrganization(orgId);
          }
        }
      }
    
      // Function to get the user's organization from their document
      function getUserOrganization(orgId) {
        return get(/databases/$(database)/documents/Users/$(request.auth.uid)).data.organisation.id == orgId;
      }
    }
    

    In this, you're directly passing the orgId as an argument, comparing it inside the function and returning the resulting boolean.

    Let me know if that works :)