Search code examples
firebase-realtime-databasefirebase-authenticationfirebase-security

Firebase Realtime Database Rules. Only creator can read data


This is my Database:

{
  "categories": {
    "c-NgA8_ZDjEur3HowEFVD": {
      "create_date": 1696699144485,
      "creator": "Codw8lfHuDcUox1Xe4ima15OGXi1",
      "delete_date": "",
      "description": "Am Abend ein schönes Nachtessen",
      "title": "Nachtessen",
      "update_date": ""
    }
  },
  "ideas": {
    "i-NgAD6p5s8G5rJWAQo48": {
      "category": "c-NgA8_ZDjEur3HowEFVD",
      "create_date": 1696700333404,
      "creator": "Codw8lfHuDcUox1Xe4ima15OGXi1",
      "delete_date": "",
      "description": "Essen im Vito in Zürich",
      "title": "Essen im Vito",
      "update_date": ""
    }
  }
}

This are my Rules:

{
  "rules": {
    "categories": {
      ".indexOn": ["creator"],
      "$category_id": {
        ".read": "data.child('creator').val() === auth.uid",
        ".write": "!data.exists()"
      }
    },
    "ideas": {
      ".indexOn": ["creator"],
      "$idea_id": {
        ".read": "data.child('creator').val() === auth.uid",
        ".write": "!data.exists()"
      }
    }
  }
}

React Typescript Code:

 const categoriesRefOrdered = query(
        categoriesRef,
        orderByChild('creator'),
        equalTo(account.uid),
      );
      const unsubscriber = onValue(categoriesRefOrdered, (snapshot) => {
        const val: CategoriesObjectType = snapshot.val();
        if (val) {
          const array = objectToArray(val);
          dispatch(initCategories(array));
        } else {
          dispatch(initCategories(null));
        }
      });

I tried the same without the $category_id row.

"creator" String is the users uid. And my try is to only let the creator read his data.

I tried this for debuging:

Simulation results Inquiry details

{
  "auth": {
    "uid": "Codw8lfHuDcUox1Xe4ima15OGXi1",
    "token": {
      "sub": "Codw8lfHuDcUox1Xe4ima15OGXi1",
      "firebase": {
        "sign_in_provider": "password"
      },
      "email": "",
      "email_verified": false
    }
  },
  "resource": {
    "key": "value"
  },
  "path": "/categories",
  "method": "get",
  "time": "2023-10-09T13:07:39.316Z",
  "isAdmin": false
}

Result details Line 5 (/categories) read: "data.child('creator').val() === auth.uid"


Solution

  • Your code tries to read data from the categories path in your database, but your security rules don't grant anyone read access to that path - so the rules reject the query.

    To securely query the data you'll want something like this:

    {
      "rules": {
        "categories": {
          ".indexOn": ["creator"],
          ".read": "auth.uid !== null &&
                query.orderByChild === 'creator' &&
                query.equalTo === auth.uid",
          ...
    

    Now the rules allow the user to read categories as long as the filter on creator having the same value as their own UID, which you code seems to do.