Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase security rule gives permission denied?

I'm struggling to set the proper security rules for my application.

An overview of the application I'm writing is that users can register themselves using email and password (I'm using Firebase Simple Login for this which works perfectly). Once logged in, user can add their todos.

angularFire('https://<firebase>/firebaseio.com/todos', $scope, 'todos');

And to add a new todo against any user, I simply update the todos model.

$scope.todos.push({
   user: '[email protected]',
   todo: 'What to do?'
});

This security rules I'm using to restrict non-registered user to add any todo:

  {
    "rules": {
      ".read": true,
      "todos": {
        ".write": "auth != null",
        ".validate": "auth.email == newData.child('user').val()"
      }
    }
  }

But it does not allow even an authenticated user to write any data and throwing an error, "FIREBASE WARNING: on() or once() for /todos failed: Error: permission_denied."

But If I add the following data in simulator then it works as expected.

{user: "[email protected]", todo: 'What to do?'} 

Here is the log:

/todos:.write: "auth != null"
    => true
/todos:.validate: "auth.email == newData.child('user').val()"
    => true
/todos:.validate: "auth.email == newData.child('user').val()"
    => true

Write was allowed.
like image 895
codef0rmer Avatar asked Sep 07 '13 15:09

codef0rmer


1 Answers

push adds a new child with a randomly generated ID (in chronological order) to /todos. So, newData isn't pointing to what you think it is pointing to. Change your rules to:

{
  "rules": {
    ".read": true,
    "todos": {
      "$todoid": {
        ".write": "auth != null",
        ".validate": "auth.email == newData.child('user').val()"
      }
    }
  }
}

Update: Above rule is valid but angularFire currently writes the whole array back to the server causing the auth to fail. You can use angularFireCollection instead, to only write the new TODO back, like so:

$scope.todos = angularFireCollection(new Firebase(URL));

$scope.todos.add({user: '[email protected]', todo: 'What to do?'});

There's an open issue to optimize angularFire's behavior when new items are added to the list, but in the meantime you can use angularFireCollection to get the right behavior.

like image 78
Anant Avatar answered Oct 17 '22 01:10

Anant