Firebase security offers a lot of flexibility on how stored data can be read and written. With Ember we will be taking some data and protecting it while handling routing issue.

My previous post of Firebase's simple login with Ember had a lot to be desired. For the most part it worked as a good proof of concept. However it needed some work. If you have not read my previous post please do so. This post will be giving suggestions using Firebase security to make the last application better. (Github Repo forthcoming)

Routes

My previous post used an authed variable as a way to keep track when a user was logged in or not. This is fine for simple use cases however it isn't always suitable in protecting routes. Due to the nature of client side apps some people can change the javascript to leave everything open.

A better way of protecting routes (and data) is to use Firebase's security. First log into the Firebase dashboard. Next click on the security rules icon.

Firebase security uses a javascript like syntax to create rules. It integrates with the simple login api to make it easier to protect data.

One simple and obvious addition is to only allow logged in users to read or write data.

    "posts":{
      ".write":"auth != null",
      ".read": "auth != null"

    },

Now when a user navigates to a page that displays post data they'll have to be logged in to see it or write to it.

The next part is a little more tricky. So if a user isn't logged in what happens if you try to access a page that is loading the posts model? You'll get this error which you can see if you look at your console log in Chrome.

permission_denied: Client doesnt have permission to access the desired data. Error: permission_denied: Client doesnt have permission to access the desired data.  
    at Error (native)

Ember can trap for this and use it to redirect to another page. The easiest way of doing this is to use error substates. Error events, like permission denied, bubble upward. We can handle this error event and use it to transition elsewhere.

//action in route file
...
    error: function(erorr) {
                return this.transitionTo('login');
        }

This is an easy way to protect your route by using Firebase security.

Login

Another issue with my last post was how to handle logging in. The original code looked like this.

//app/routes/index.js
import Ember from 'ember';

export default Ember.Route.extend({  
  actions: {
    login: function() {
        this.get('auth').login();
    },

    logout: function() {
      this.get('auth').logout();
    }
  }
});

The problem with this approach is that after calling login a popup window will appear. The user will then need to login and the application needs to handle all the various scenarios.

Ideally we would need to redirect the user to the logged in area of the application after the user sucessfully logs in. Unfortunately the code above doesn't handle this scenario.

There are probably many ways to handle this, but one easy way is to call the login for the actual authClient firebase object.

  actions: {
    login: function() {
        var route = this;
        (this.get('auth').authClient.login('twitter')).then(function(){
                return route.transitionTo('index');
        },function(error){
                alert('error could not login! ' + error);
        }
        );
    }

  }

This uses a promise that will be fullfilled after the user succesfully logs in. We can then successfully transition to index. If an error occurs we can display an error instead.

Controller

One last improvement to my last post is to improve the logic on adding posts. After saving a post it never updates the curent posts on screen. In addition the text boxes never got cleared. The user has to refresh the page to see if it worked. An easy way of fixing both of these issues is to add a promise after the save function. After the post is successfully saved we'll then clear the text boxes. The new index controller looks like this.

//index.js controller
...
var controller = this;  
     newPost.save().then(function(newPost){
                controller.set('post.title', '');
                controller.set('post.body', '');
        });
    }

Part 2

Part 2 of this tutorial will give another example using Firebase security and more ways of protecting your application.