1

I'm new to Firebase, and I'm trying to understand rules where authenticated user id is to be used for securing data. I'm using Angularfire2 on the client. And I'm using email/password authentication, which works fine.

If I set my database rules to allow read and write for authenticated users, everything works fine, and I end up with the following data in the Firebase database...

{
  "notes" : {
    "-KmgjG9hxoXOTtuLTItz" : {
      "content" : "test",
      "title" : "Test note 1",
      "uid" : "iLH4Kg20shViwJebCmU8Ynp0OG23"
    },
    {
    "-Kmh5igvItrJstbAhRpq" : {
      "content" : "test",
      "title" : "Test note2",
      "uid" : "iLH4Kg20shViwJebCmU8Ynp0OG23"
    }
  }
}

Now I want to restrict read and write permissions where the authenticated user matches the user id (uid) set on each object, so I changed the rules as follow...

{
  "rules": {
    "notes": {
      ".read": "data.child('uid').val() == auth.uid",
      ".write": "newData.child('uid').val() == auth.uid"
    }
  }
}

However, this does not work. Reads fail with...

ERROR Error: permission_denied at /notes: Client doesn't have permission to access the desired data.

...and writes fail with...

FIREBASE WARNING: set at /notes/-KmgjG9hxoXOTtuLTIpG failed: permission_denied

I know that the user is authenticated because if I hard-code the user id in the rules like below, it works just fine...

{
  "rules": {
    "notes": {
      ".read": "auth.uid == 'iLH4Kg20shViwJebCmU8Ynp0OG23'",
      ".write": "auth.uid == 'iLH4Kg20shViwJebCmU8Ynp0OG23'"
    }
  }
}
d60402
  • 3,190
  • 2
  • 23
  • 28
  • With your security rules, each user can access each note that they own. But no user can get a list of notes. This is working as designed and is known as "rules are not fitlers" in Firebase terms. I recommend reading about that [in the Firebase documentation](https://firebase.google.com/docs/database/security/securing-data#rules_are_not_filters) and in one of the [many questions about it](https://www.google.com/search?q=site:stackoverflow.com+firebase+rule+are+not+filters), including [this original one](https://stackoverflow.com/questions/14296625/). – Frank van Puffelen Jun 15 '17 at 19:21

2 Answers2

2

I was able to solve this by restructuring my data schema, putting the user id in the path, not in the object, e.g., /users/<-uid->/notes/, and using the following rules...

{
  "rules": {
    "users": {
      "$userId": {
            ".read": "$userId === auth.uid",
            ".write": "$userId === auth.uid"   
      }
    }
  }
}

As per the comments regarding "rules are not filters", I get that now. The thing that was tripping me up was where the Firebase database rules doc was referring to "children" with key-value pairs, e.g.,...

This example only allows reading if the isReadable child is set to true at the location being read.

".read": "data.child('isReadable').val() == true"

To me that implied that the JSON data structure is something like this...

{ ..., isReadable: true, ...}

But I guess that is referring to location paths, e.g., /users/fred/isReadble or something like that. Not quite sure. It seems odd. But regardless, I got it working.

d60402
  • 3,190
  • 2
  • 23
  • 28
0

I think you are forgetting the key:

{
  "rules": {
    "notes": {
      "$key": {
        ".read": "auth.uid == 'iLH4Kg20shViwJebCmU8Ynp0OG23'",
        ".write": "auth.uid == 'iLH4Kg20shViwJebCmU8Ynp0OG23'"
      }
    }
  }
}

I might be missing something else but you are targeting a list with autogenerated keys (accessible in your rules with a "$somevar").

R_Ice
  • 634
  • 6
  • 7
  • You're right that the rule would have to be lower in the tree to allow access to the individual notes. But a read from `/notes` would still fail with your rules. Firebase security rules cannot be used to filter data. See my comment to the question for some links. – Frank van Puffelen Jun 15 '17 at 19:22
  • @Frank van Puffelen is right, database rules are not filters (you did forget about the key however but that is not the point). I remember encountering this same (annoying) problem and I solved part of it using cloud functions (https://firebase.google.com/docs/functions/). See https://stackoverflow.com/questions/38687594/firebase-rule-that-works-like-a-filter to start with (it might force you to change your schema). – R_Ice Jun 15 '17 at 19:30