firebase firestore rules authenticated access to all collections except one

Viewed 8809

I have the following firestore structure, basically 3 collections

publicdata protecteddata1 protecteddata2

I want to have protecteddata1 and protecteddata 2, and really the entire firestore database as authenticated users only. But i want the public to have readonly access to 'publicdata' collection..

The following is my attempt but it doesn't work

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read;
      allow write: if (request.auth.uid != null);
    }
    match /publicdata {
       allow read;
    }
  }
}
3 Answers

The recursive wildcard here is allowing access to all collections:

    match /{document=**} {
      allow read;
      allow write: if (request.auth.uid != null);
    }

Once any rule allows access to a collection, that access cannot be revoked by any other rule.

What you will have to do is call out each individual collection in its own rule. Yes, that's kind of a pain, but it's your only option. It also makes it very clear to the reader of your rules what you intend to allow for each collection.

Also worth noting that this rule doesn't actually do anything at all, because it doesn't match any documents:

    match /publicdata {
       allow read;
    }

If you want to match documents in the publicdata collection, it needs a wildcard that matches document within that collection:

    match /publicdata/{id} {
       allow read;
    }

Remember that rules match documents for access, not collections.

You can use the following functions I created to do this

function isUserAuthenticated() {
    return request.auth.uid != null; 
}

You can then use it like this:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if isUserAuthenticated();
    }
    
    match /publicdata/{itemId} {
      allow read : if true;
      allow create : if isUserAuthenticated();
      allow update: if isUserAuthenticated();
      allow delete: if isUserAuthenticated();
    }

    /* Functions */
    function isUserAuthenticated() {
      return request.auth.uid != null; 
    }
  }
}   

Because here is says:

Overlapping match statements

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: ...

You can use this:

rules_version = '2';
service cloud.firestore {

  // Check if the request is authenticated
  function isAuthenticated() {
    return request.auth != null;
  }

  match /databases/{database}/documents {
    match /{document=**} {
        allow read, write: if isAuthenticated();
    }
    match /publicdata/{document=**} {
        allow read: if true;
    }
  }
}
Related