Search code examples
backbone.jshashfirebaseuser-rolesfirebase-security

Implementing "read" and "write" security rules in Firebase


In my app I want to have a "can read"- and a "can write" view. When the app starts without existing parameters ("first time user"), then 2 random hashes are created, together with the firebase app secret they are POSTed to the PHP FirebaseTokenGenerator to receive my token.

Then I want to do this:

  • The first hash ("read hash") represents an "anonymous user" entry
  • The second hash ("write hash") represents a "key" which is a child entry of the user entry

Which looks like this:

<appname>
    users
        <read_hash>
            key
                <write_hash>
            [other user related data]
                ...

The hashes can be used as URL parameters, e.g. "myapp.com/#read_hash/write_hash"

What I want to achieve is:

  • when the user only has his read_hash (calling just "myapp.com/#read_hash"), he should be able to SEE all his entries he entered the first time (having the app create the write_hash / "key" for him). But he is not allowed to modify them.
  • When he provides his write_hash (calling "myapp.com/#read_hash/write_hash") writing to Firebase is allowed.

My security rules:

{
    "rules": {
        "users": {
            "$user": {
                ".read": "$user == auth.read_hash",
                ".write": "$user == auth.read_hash && root.child('users').child($user).child('key').val() == auth.write_hash"
            }
        }
    }
}

My problem is: How do I store the write_hash the first time without my security rule ".write" preventing writing ??

Any other idea how to achieve this? Any architectural / inconsistencies?

I'm using these libs:

  • Backbone JS with backbone-firebase.js
  • FirebaseTokenGenerator PHP

Thanks in advance.


Solution

  • First, I should note that you should never put the Firebase Secret in your app. It should always be stored safely on a secure server. Your original question suggested you were sending the token down to a server from the client.

    I would suggest having the read_hash be the same as a user id, and then storing a "key" at //key when the user is first created.

    Then I'd suggest a rules structure as follows:

    {
      "rules": {
        "$userid": {
          ".read": "$userid == auth.read_hash",
          ".write": "!data.exists() || ($userid == auth.read_hash && data.child("key") == auth.write_hash)",
        }
      }
    }