Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Configure the firestore security rules to allow users to only access their own data - efficiently

Using firestore with angularfire2 rc 2.

All is working very nicely in development with no effective security rules.

These are the no security rules - where the client code will create, update and delete collections below the $COLLECTION_NAME/document without issue.

service cloud.firestore {
    match /databases/{database}/documents {
        match /collectionA/{userId=**} { 
            allow read, write: if true;
        }
        match /collectionB/{userId=**}  {
            allow read, write: if true;
        }
        match /collectionC/{userId=**}  {
            allow read, write: if true;
        }
        match /collectionD/{userId=**}  {
            allow read, write: if true;
        }
    }
}

Where I want to get to is to only allow users to access their own data.

I started out with the following rules:

service cloud.firestore {
    match /databases/{database}/documents {
        match /collectionA/{userId=**} { 
            allow read, write: if request.auth.uid == userId;
        }
        match /collectionB/{userId=**}  {
            allow read, write: if request.auth.uid == userId;
        }
        match /collectionC/{userId=**}  {
            allow read, write: if request.auth.uid == userId;
        }
        match /collectionD/{userId=**}  {
            allow read, write: if request.auth.uid == userId;
        }
    }
}

However, as soon as I add any sort of restrictive rule including even just validating the request is authorised.

match /databases/{database}/documents {
    match /collectionA/{userId=**} { 
       allow read, write: if request.auth;
    }
    match /collectionB/{userId=**}  {
        allow read, write: if request.auth;
    }
    match /collectionC/{userId=**}  {
        allow read, write: if request.auth;
    }
    match /collectionD/{userId=**}  {
         allow read, write: if request.auth;
    }
}

I get code permission errors.

[code=permission-denied]: Missing or insufficient permissions.

FirebaseError: Missing or insufficient permissions.

Each {userId} document contains a collection which in turn contains documents so a full path might be something like

const entryCollection: AngularFirestoreCollection<Entry> = this.angularfirestore.collection('collectionC/' + user.uid + '/records' + '/2017-40' + '/entries');

The requests should be authenticated as the access is only granted in the client following authentication using firebase authentication. Logging indicates the uid is present and indeed when creating the document below collectionA or B or C or D the user.uid document is named using the uid.

like image 929
Mark Eames Avatar asked Oct 07 '17 07:10

Mark Eames


People also ask

How do you secure firestore rules?

To set up and deploy your first set of rules, open the Rules tab in the Cloud Firestore section of the Firebase console. Write your rules in the online editor, then click Publish.

How do I change security rules in Firebase?

Edit and update your rulesOpen the Firebase console and select your project. Then, select Realtime Database, Cloud Firestore or Storage from the product navigation, then click Rules to navigate to the Rules editor. Edit your rules directly in the editor.


2 Answers

The short answer is that {userId=**} results in userId being a path and not a string. This means that comparing it to request.auth.uid (which is a string) will fail. Instead, you'll likely want something like:

service cloud.firestore {
    match /databases/{database}/documents {
        match /collectionA/{userId}/{allSubcollections=**} { 
            allow read, write: if request.auth.uid == userId;
        }
    }
}

This will guarantee that userId is a string, and then match the appropriate subcollections (note that again, allSubcollections will be a path).

like image 184
Mike McDonald Avatar answered Nov 04 '22 00:11

Mike McDonald


In my case, I needed the permissions for creating the user as well so the other solutions did not work for me. I had to also allow access to /users/{userId}. Here is my code:

service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, write: if request.auth.uid == userId;
      match /{allSubcollections=**} {
        allow read, write: if request.auth.uid == userId;
      }
    }
  }
}
like image 26
Zane Campbell Avatar answered Nov 04 '22 01:11

Zane Campbell