Firebase Permission denied when reading data after authentication

Solution 1:

Firebase's permission model only allows the user access to data that you explicitly give access to. Since in your security rules, you only give access to /users/$uid, the user cannot read from root /. The Firebase documentation covers this under "rules cascade".

You seem to want to use security rules to filter data, which is not possible with Firebase's security model. See the section "rules are not filters" in the Firebase documentation as well as these previous questions and answers:

  • firebase security permission not working
  • firebase rules not working
  • How to use Firebase rules to only give permission to certain leaf nodes

The simplest solution is to allow read of the users node:

{
    "rules": {
        "users": {
            ".read": "auth !== null && auth.provider === 'password'"
        }
    }
}

And then query on that level:

getData(ref.child("users"));

Solution 2:

I got this exception using a slightly different approach to read from my database, but this is how I solved the issue.

First of all, my database rules looked liked this:

{
"rules": {
  "student": {
    "$uid": {
      ".write": "auth != null && auth.uid == $uid",
      ".read": "auth != null && auth.uid == $uid"
      }
    }
  }
}

Earlier on, to write to to the student database, I used this code in my Activity:

 mAuthListener = new FirebaseAuth.AuthStateListener() {
        @Override
        public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
            user = firebaseAuth.getCurrentUser();
            if (user != null) {
                // User is signed in
                Log.e(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
            } else {
                // User is signed out
                Log.e(TAG, "onAuthStateChanged:signed_out");
            }
            // ...
        }
    };
    ...
    Student student = new Student();
    student.setPhoneNumber("+23480547455343");
    student.setCountryOfOrigin("Nigeria");
    mDatabaseReference.child("student").child(user.getUid()).setValue(student).
                addOnCompleteListener(DetailsCaptureActivity.this, 
                                   new OnCompleteListener<Void>() {
     ...
     });

Notice how the child name (student) matches the child name in the firebase data rules?

Now to read the data of this user, I did this:

 //Set up an AuthStateListener that responds to changes in the user's sign-in state:
    mAuthListener = new FirebaseAuth.AuthStateListener() {
        @Override
        public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
            user = firebaseAuth.getCurrentUser();
            if (user != null) {

                   databaseReference = firebaseDatabase.getReference().child("student").child(user.getUid());
                   databaseReference.addValueEventListener(new ValueEventListener() {
                      @Override
                      public void onDataChange(DataSnapshot dataSnapshot) {
                          Student student = dataSnapshot.getValue(Student.class);
                          phoneNumberTextView.setText(student.getPhoneNumber());
                      }

                      @Override
                      public void onCancelled(DatabaseError databaseError) {

                          Log.e(TAG, databaseError.getMessage());
                      }
                  });

            } else {
                Log.e(TAG, "onAuthStateChanged:signed_out");
            }
        }
    };

I got the permission denied exception if I did only:

databaseReference = firebaseDatabase.getReference().child(user.getUid());