How to add rule in Firebase to prevent read of parent element?

Solution 1:

You're hitting a few common problems here, so let's go through them one by one.

1. Security rules can't filter data

You're trying to control in your rule on /applications what application will be returned when a user tries to read that node. Unfortunately that is not possible, because security rules grant all-or-nothing access.

So either the user has access to /applications (and all data under it), or they don't have access to it. You can't set a rule on /applications to grant them access to some child nodes.

In the documentation, this is referred to as rules are not filters and the fact that permission cascades.

2. Avoid nesting data

You're trying to grant access to /applications, but then store two types of data under there for each application. In cases like that, it is usually better to store each type of data as its own top-level list.

So in your case, that'd be:

{
  "application_features": {
    "id_1": {
      "a": true,
      "b": false
    },
  },
  "application_users": {
    "id_1": {
      "user_id_1": true,
      "user_id_2": true
    }
  }
}

This allows you to grant separate access permissions for the application users and its features. While it means you'll have to read from both branches to get all information of each user, the performance difference there is negligible as Firebase pipelines those requests over a single socket

For controlling access and the most scalable data structure, Firebase recommends that you avoid nesting data and flatten your data structure.

3. Model the data in your database to reflect the screens of your app

Since granting anyone access on /applications gives them access to all data under that, you'll likely need another place to store the list of applications for each user.

I usually make this list explicit in my databases, as another top-level list:

{
  ...
  "user_applications": {
    "user_id_1": {
      "id_1": true
    },
    "user_id_2": {
      "id_1": true
    }
  }
}

So now when you want to show the list of applications for the current user, you load the IDs from /user_applications/$uid and then look up the additional information for each app with extra calls (which in turn can be pipelined again).

This one is not in the documentation, but a common pattern with NoSQL databases. I recommend checking out my answers to Many to Many relationship in Firebase and Firebase query if child of child contains a value.