Search code examples
angularfirebasefirebase-securityangularfire2google-cloud-firestore

Trying to set up Cloud Firestore security rules using request.path


I am struggling to get my head around some Firestore security concepts. I want to set up a rule based on the request.path property.

My rule is this:

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.path[0]=='appUsers';
    }
  }
}

...and I then use AngularFire2 to add a document like this...

this.myAngularFirestore.doc('/appUsers/'+this.auth.auth.currentUser.uid).set({name: this.auth.auth.currentUser.displayName})
      .then(()=>console.log('Added user'))
      .catch(err=>console.log('Could not add user:', err.message));

I thought this should be simple based on the docs but all I ever get is the error - Missing or insufficient permissions.

I know I am logged in correctly and I know the query works if I open up the security with allow read,write: if true; so what am I not getting here? Shouldn't request.path[0] evaluate to the string appUsers here and so allow the data to be written?

Any ideas gratefully accepted as I'm not finding these rules much fun to out together so far.

Cheers all


Solution

  • I'd recommend using the built-in path matcher version of this:

    service cloud.firestore {
      match /databases/{database}/documents {
        match /appUsers {
          allow read, write;
        }
      }
    }
    

    Or, if you really want to specify in the condition:

    service cloud.firestore {
      match /databases/{database}/documents {
        match /{pathSegment} {
          allow read, write: if pathSegment == "appUsers";
        }
      }
    }
    

    request.path is the full path (e.g. /projects/<projectId>/databases/(default)/documents/appUsers, which means you'd actually want request.path[5] (hence why we provide easier, more readable ways of doing this).

    Edit (4/2/18): request.path supports both List and Map access:

    • List: request.path[5] == "appUsers"
    • Map: request.path['pathSegment'] == "appUsers", though note that it only works on wildcarded (e.g. {name}) values