Sergio76
Sergio76

Reputation: 3986

Realtime database firebase rules - denied permission

I have a problem that I have found information on various websites or forums, but I cannot find a solution that works for me.

I have this realtime database structure in firebase:

enter image description here

I want to apply security rules. Applying the following rules, only correctly authenticated users can obtain the information.

{
  "rules": {
    ".read": "auth != null",
    ".write": "auth != null"
  }
}

So far, everything works correctly. Logically, it indicates that any authenticated user can access any information

Now i want the authenticated user to only access their nodes.

Based on the information I've found, this should be easy using these rules:

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

However, I always get the error:

W / SyncTree: Listen at / failed: DatabaseError: Permission denied

This is the connection made from the android code:

 database.addListenerForSingleValueEvent(object :
            ValueEventListener {
            override fun onDataChange(dataSnapshot: DataSnapshot) {

                val path = dataSnapshot.child(App.res.getString(R.string.word_user))
                    .child(prefs.user_id.toString()).child("expenses").children

                for (snapshot in path) {
...

I don't understand where the problem is.

I know the request is made to the "expenses" field, but being included inside the "users" field, I suppose there should be no problem.

As I have said, I have read a lot about it, but I cannot get it to work.

Thanks in advance

Upvotes: 1

Views: 322

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598648

From the error message it looks like you're attaching a listener to the root of the database. When you try to do this, Firebase checks if you have permission to read the root. Your rules grant nobody permission to read the root of the database, so the read is rejects.

It is important to realize that rules don't filter data, but they merely enforce that all access to the data follows the rules. Since you only grant access to /users/$uid, you can only attach a listener to /users/$uid or lower.

The solution is to move the path building that you now do inside onDataChange to just outside of that:

database
  .child(App.res.getString(R.string.word_user))
  .child(prefs.user_id.toString())
  .child("expenses")
  .addListenerForSingleValueEvent(object : ValueEventListener {
    override fun onDataChange(dataSnapshot: DataSnapshot) {
        for (snapshot in dataSnapshot.children) {
            ...

This not only ensures your code is allowed to read the data, but also means it tries to download much less data (which saves both you and your users money and time).

Also see:

Upvotes: 2

Related Questions