Tuesday 20 October 2020

Firebase Realtime Database rules not working in frontend

Specific TLDR: The rule ".read": "auth != null && data.child('userEmail').val() === root.child('users').child(auth.uid).child('email').val()" should work as expected in the app.

I've followed the documentation and in the rules playground the test works so I think it has to do with the way I'm authenticating maybe? I'll provide the info below and hopefully someone can answer this soon.

Realtime Database structure:

"db-name": {
  "units": {
    0: {
      "serial": "002",
      "userEmail": "s@gmail.com"
    },
    1: {
      "serial": "001",
      "userEmail": "r@gmail.com"
    }
  },
  "users": {
    "R6nlZ...": {
      "email": "r@gmail.com"
    },
    "qwerty...": {
      "email": "s@gmail.com"
    }
  }
}

Rules object:

{
  "rules": {
    // ".read": "now < 1604037600000",  // 2020-10-30
    // ".write": "now < 1604037600000",  // 2020-10-30
    "units": {
      ".indexOn": "userEmail",
      "$key": {
        ".read": "auth != null && data.child('userEmail').val() === root.child('users').child(auth.uid).child('email').val()",
        ".write" : "auth != null && data.child('userEmail').val() === root.child('users').child(auth.uid).child('email').val()"
      }
    },
    "users": {
      "$uid": {
        ".read": "$uid === auth.uid",
        ".write": "$uid === auth.uid"
      }
    }
  }
}

Rules test: Simulation type: read Location: https:db-name.firebaseio.com/units/1 Auntenticated: yes Provider: Anonymous UID: R6nlZ... Result: Simulation read allowed

If I try to get /units/0 I get denied which is what I expect because that's a unit that the current auth'd user doesn't have permission to see.

Now if I do this in plain javascript I don't get the same result as I do in the Rules Playground in the Firebase Console.

<!-- Add the entire Firebase JavaScript SDK -->
    <script src="https://www.gstatic.com/firebasejs/7.24.0/firebase.js"></script>

    <script>
    // import * as firebase from "firebase";
    var firebaseConfig = {
      apiKey: "...",
        authDomain: "...",
        databaseURL: "...",
        projectId: "...",
        storageBucket: "...",
        messagingSenderId: "...",
        appId: "..."
    };
    // Initialize Firebase
    firebase.initializeApp(firebaseConfig);

    var email = 'r@gmail.com';
    var password = '123456';
    // Sign in existing user
    firebase.auth().signInWithEmailAndPassword(email, password).then(function() {
      console.log('Signed in as: ' + firebase.auth().currentUser.email);

      var dbUnits = firebase.database().ref().child('units').orderByChild('userEmail').equalTo(firebase.auth().currentUser.email);
      var getUnitsDetails = function() {
        return dbUnits.once('value').then(function(snapshot) {
          snapshot.val() ?
          Object.entries(snapshot.val()).map((unit) => {
            return (
              console.log('Serial number of unit: ' + unit[1].serial + ' & Owner of unit: ' + unit[1].userEmail)
            )
          })
          :
          console.log('no units found for that user bro')

        })
      }
      console.log(getUnitsDetails());


    }).catch(function(error) {
      console.log(error);
    });

When I have a Firebase permissions set as they are above in the rules I pasted, the user r@gmail.com can't see any units. If I let the read permissions be fully open (not what I want) then that user can see their unit(s).

To me this doesn't make sense because I thought auth.uid is what Firebase can see when the user is logged in no matter what login type they use.



from Firebase Realtime Database rules not working in frontend

No comments:

Post a Comment