4
votes

For a Firebase Database that is having email/password based authentication enabled, how we can grant read/write access to users who signin to a Firebase backed iOS application. Though Firebase iOS SDK exposes auth api to create/signin/signout users but I could not find any api in firebase SDK that can provide read access or write access to a user.

Lets suppose I create two users user1, user2 using the api. How can I grant read access to user1 and read /write access to user2. The needed access is on the whole database.

Is it possible via Security Rules (as provided via JSON in Rules section under Database tab in google firebase console) only? If Yes, how we can create such kind of read/write access for different users? If it is possible via Firebase iOS SDK then which api to use?

Thanks

1
The security model for the Firebase Database is discussed in the documentation here: firebase.google.com/docs/database/security. It is enforced on the Firebase servers, so not specific to your iOS client. I recommend that you study the documentation, try to make it work for your use-case and come back here if you have a problem implementing the rules.Frank van Puffelen

1 Answers

6
votes

It was very hard for me to understand to start with, but the rules are very flexible and let you base access to your data based on other database contents. Basically you grant access to a node and that grant applies to all children as well and can't be removed from deeper nodes in the tree. You can apply those database rules in the console, but there must be an api if you need to use it as well to set the rules for the entire database. They do have to be a single document, so you wouldn't want to hard-code users, but you could put them in a hidden and inaccessible node, the rules have access to it.

For instance let's say you want to let people request to be friends with other people, and for the other person to be able to accept and add both people to the friends list. You could have a schema similar to this:

uid
  "friends"
    friendUid1
    friendUid2
    friendUid3
  "private"
    ... some private data your friends can read
"friendRequests"
  targetUid
    requestorUid -> can be written to only by requestorUid

The first step is writing a value to friendRequests/$targetUid/$requestorUid. The ONLY person that can write to this node is the one authenticated as requestorUid. targetUid would be granted read access to targetUid node so they could read it because it is a child, but not write it.

Then you could grant write access to $requestor/friends/$targetUid to $targetUid based on the existence of friendRequests/targetUid/requestorUid. This allows the person that received the friend request to write their OWN uid to the requestor's friend list, but only if the requestor had already write their own uid in a request to be a friend. They would then write the requestor's uid to their own friends list. If the uid of a logged-in user is in their friends list, they can access the private data.

{
  "rules": {
    "$uid": {
      ".read": "auth.uid === $uid",
      ".write": "auth.uid === $uid",
      "friends": {
        "$friendId": {
          ".write": "root.child('friendRequests').child($friendId).child($uid) && auth.uid === $friendId"
        }
      },
      "private": {
        ".read": "data.parent().child('friends').child(auth.uid).exists()"
      }
    },  
    "friendRequests": {
      "$targetUid": {
        ".read": "auth.uid === $targetUid",
        "$requestorUid": {
          ".write": "auth.uid === $requestorUid"
        }
      }
    }
  }
}

Let's use some "real" ids and say that uid 100 wants to be friends with uid 200. They would write their own id 100 to be a request for 200, this is allowed because auth.uid will match $requestorUid and match the last write rule:

ref = db.getReference("friendRequests/200/100");
ref.setValue(true);

When user id 200 logs in, they can read all their friend requests at friendRequests/200. They see that user 100 requested to be their friend, so they first add 100 to users/200/friends. This is allowed because auth.uid will be 200 and they have full read/write access to the entire users/200 node and all its children.

Next they can also write to users/100/friends/200 because this rule:

"root.child('friendRequests').child($friendId).child($uid) && auth.uid === $friendId"

auth.uid will be 200 and the check will see that 100 asked to become friends with 200 because friendRequests/200/100 exists and that node is only writable by user 100.