Christian BouvierNov 25, 2016

AngularJS ui.router per view authorization

Most AngularJS applications need a routing mechanism to allow for navigation among it’s potentially multiple states. One of the most popular tools to do this is ui.router, which is awesome!

Using it, we face a situation in which some routes can be accessed by anyone, while others require authorization. For this cases we use the following elegant and easy mechanism, which consist of 3 simple steps.

  • Add a boolean attribute authenticate to each ui.ruoter state and choose a proper value for it.
// ------------------------------------------------------------
// Public page - Authentication is NOT required.
// ------------------------------------------------------------
.state('public-page', {
    url: '/',
    authenticate: false,
    other attributes...
})

// ------------------------------------------------------------
// Private page - Authentication IS required.
// ------------------------------------------------------------
.state('private-page', {
    url: '/private-page',
    authenticate: true,
    other attributes...
})
  • Handle the user authentication status in some place that could be easily reached, like a service. It would be a good idea to have an Authentication service in charge of having the information about the authentication status, and a method to access this information (let’s say, AuthenticationService.isAuth())

  • Check for every state transition if the page that the user is trying to access is public or requires authentication, and based on that, complete the transition or abort it. A good place to perform this check is in the application’s run method.

.run(['$rootScope', '$state', 'authService', function($rootScope, $state, AuthenticationService) {

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

        if (toState.authenticate && !AuthenticationService.isAuthenticated()) {
            // Remember toState and toStateParams.
            $rootScope.toState = toState.name;
            $rootScope.toStateParams = toParams;
            // Abort transition
            event.preventDefault();
            // Redirect to login page
            $state.go('login');
        }
    });
}])

Then, another interesting thing that you can do is to remember the toState value, to redirect to when the login succeeds.

if ($rootScope.toState && $rootScope.toState !== 'login') {
    $state.go($rootScope.toState, $rootScope.toStateParams).then(function() {
        // Reset toState and toStateParams.
        $rootScope.toState = undefined;
        $rootScope.toStateParams = undefined;
    });
} else {
    $state.go('home');
}

That’s it. Simple and elegant, isn’t it?