Wednesday, February 10, 2016

Firebase #1: Synchronise User's Private Data

Are you developing Android, iOS or Web app and do you want to store user's private data in the cloud so users have their data on all of their devices without you having to write a single line of server code? In this blog post I am going to present a simple solution using Firebase. Firebase is JSON NoSQL cloud database, it is free if you have less than 100 users online at the same time. I will focus on the Android implementation. This is not meant to be a complete step by step guide. Read the whole article first to get you the idea and then follow the provided links to go deeper.

Since this is the simplest solution to get you started there some limitations:
  • Each user has just his own private data. There is no sharing between users and no public access.
  • Just one method of authentication can be used in the app. e.g. just Google or just Facebook or just Email. Developer can choose any method and hard code it, but then it is not possible for the user to choose his preferred method of authentication.
Both of these limitations can be addressed. I might get to it in future posts. Here is some solution on stackoverflow: How can I login with multiple social services with Firebase? I'm not sure if their solution is secure.

After you go through the Firebase's Android Quickstart you know how to read and write data to and from firebase database, but anybody has access to the whole database so we want implement security rules so each user has access only to his own data.

Each user will have its own private subtree in Firebase database. The firebase url is going to look like this https://yourapp.firebaseio.com/{$user_id}/ anything after the {$user_id} path is accessible only by the authenticated user.

Here are Firebase rules to make it happen. You put them into "Security & Rules" page in firebase dashboard https://yourapp.firebaseio.com/?page=Security.

1
2
3
4
5
6
7
8
{
  "rules": {
    "$user_id": {
      ".read": "auth !== null && auth.uid === $user_id",
      ".write": "auth !== null && auth.uid === $user_id"
    }
  }
}

These rules mean that the root level path of each object is going to be a user id. Anything nested underneath it can be read and written only by authenticated user which user id is equal to the one in the root path of the object.

I definitely recommend you to read more about Firebase security.

Now I am going to get little bit deeper into Android implementation details.

I implemented Facebook authentication. It was straight forward. I followed this guide: https://github.com/firebase/FirebaseUI-Android#using-firebaseui-for-authentication and then this: https://www.firebase.com/docs/android/guide/login/facebook.html

Then I decided to switch to Google authentication and it was when the fun begun. It took me a while to resolve a few issues. I also followed the guides here: https://github.com/firebase/FirebaseUI-Android#using-firebaseui-for-authentication and here: https://www.firebase.com/docs/android/guide/login/google.html but it didn't go so smoothly. There is a little catch that you have to create two different google OAuth client ids in google developer console. One is going to be an android application where you put hash of your signing key. Other will be Web application. But the thing which doesn't make sense is that in your android app you have to actually use Web application's OAuth client id. I found it here on stack overlow: http://stackoverflow.com/questions/33583326/new-google-sign-in-android

Now you know the catch and you can follow the google guide: https://developers.google.com/identity/sign-in/android/start-integrating

Then after you have your web aplication google OAuth client id and you are using FirebaseUI https://github.com/firebase/FirebaseUI-Android#using-firebaseui-for-authentication you have to put the google client id into your manifest. They missed to mention it in FirebseUI readme.

1
2
3
4
5
6
<application>
        <!-- Google Configuration -->
        <meta-data
            android:name="com.firebase.ui.GoogleClientId"
            android:value="@string/google_client_id" />
</application>


Don't forget to enable your method of authentication in "Login & Auth" section of Firebase dashboard https://yourapp.firebaseio.com/?page=Auth and also put your client id and secret there.

Finally after you successfully authenticate user into firebase you can write into his firebase database:
1
2
mFirebase = new Firebase("http://yourapp.firebaseio.com/");
mFirebase.child(mFirebase.getAuth().getUid()).setValue(true);