I'm rewriting Kids In Touch right now with Firebase as the backend. I'm really pleased with how things are going. Developing with Firebase is so much easier than dealing with my old REST API.

Today, I was dealing with logging users into the app. Most examples I found online have authentication using resolves on each state. Example from the Firebase docs:

app.config(["$stateProvider", function ($stateProvider) {
  $stateProvider.state("home", {
    // the rest is the same for ui-router and ng-route...
    controller: "HomeCtrl",
    templateUrl: "views/home.html",
    resolve: {
      // controller will not be invoked until getCurrentUser resolves
      "currentUser": ["simpleLogin", function(simpleLogin) {
        // simpleLogin refers to our $firebaseSimpleLogin wrapper in the example above
        // since $getCurrentUser returns a promise resolved when auth is initialized,
        // we can simple return that here to ensure the controller waits for auth before
        // loading
        return simpleLogin.$getCurrentUser();
      }]
    }
  })
}]);

Of course, that works just fine. However, it's a bit painful if your app has more than a few states.

To avoid repeating the code over and over, you can take advantage of the ui-router $stateChangeStart event like this :

.run([ '$rootScope', '$state', '$ionicPlatform', '$firebaseSimpleLogin', 'BASEREF',  function($rootScope, $state, $ionicPlatform, $firebaseSimpleLogin, BASEREF) {

  var dataRef = new Firebase(BASEREF);
  var loginObj = $firebaseSimpleLogin(dataRef);

  $ionicPlatform.ready(function() {
	...
  });

  $rootScope.$on('$stateChangeStart', function (event, toState) {

    if(toState.name.indexOf('main') !== -1 ) {

      // Must be logged in to access the main app pages
      loginObj.$getCurrentUser().then(
        function(user) {

          if(!user) $state.go('entry');

        }
      );
    }

  });

}])

Each time the user tries to move to a new state, the $stateChangeStart events fires. The code above listens for that event. When the user is attempting to any of my "main" app states, they must be authenticated. If Firebase doesn't currently have a logged in user, they are instantly redirected to my "entry" state. This is where they can choose to signup or login.

This seems to be working pretty well for me. Does anyone have suggestions or concerns about doing authentication this way? If so, please let me know on Twitter.

UPDATE : While seaching for a solution to another problem, I came across an article by Jurgen Van de Moere about handling repetitive resolves.

If you are using abstract states, you can handle the resolve for all child states in the single abstract state. So, the original Firebase example could become something like this :

app.config(["$stateProvider", function ($stateProvider) {

	.state('main', {
		url : '/main',
		templateUrl : 'main/mainContainer.html',
		abstract : true,
		resolve : {
			"currentUser": ["simpleLogin", function(simpleLogin) {
			// simpleLogin refers to our $firebaseSimpleLogin wrapper in the example above
			// since $getCurrentUser returns a promise resolved when auth is initialized,
			// we can simple return that here to ensure the controller waits for auth before
			// loading
			return simpleLogin.$getCurrentUser();
		}]

	})

	.state('main.home', {
		url : '/home',
		views : {
			'main' : {
				templateUrl : 'main/home.html'
			}
		}
	}

	});
})

In that rough code sample above, every child of the "main" state would automatically get the "currentUser" resolved. That works pretty well except it doesn't handle the non-authenticated situations. There are 2 ways to deal with that. You could have EVERY controller check for authentication and bounce the user back. Or, you could change the resolve return false if not authenticated. Then, you still have to handle the resolve failure in the $stateChangeStart event.

So, if you NEED the currentUser or some other common info in every controller, the above is a great way to go. If you don't need acccess to the currentUser all the time, then I think handling it in the $stateChangeStart event is the way to go.