How to Redirect with UI Router When Session Expires in Firebase

Ken picture Ken · Sep 6, 2015 · Viewed 7.4k times · Source

I'm using Angular with Firebase and UI Router. I'm using anonymous authentication. When a session expires, I would like the unauthenticated user to be redirected to the homepage. I've used the Yeoman Angularfire Generator as a model. But when I use the code below, an authenticated page does not redirect when a user is already on that page and the session expires.

.config(['$urlRouterProvider', 'SECURED_ROUTES', function($urlRouterProvider, SECURED_ROUTES) {
    $urlRouterProvider.whenAuthenticated = function(path, route) {
        route.resolve = route.resolve || {};
        route.resolve.user = ['Auth', function(Auth) {
            return Auth.$requireAuth();
        }];
        $urlRouterProvider.when(path, route);
        SECURED_ROUTES[path] = true;
        return $urlRouterProvider;
    };
}])
.run(['$rootScope', '$location', 'Auth', 'SECURED_ROUTES', '$state',
    function($rootScope, $location, Auth, SECURED_ROUTES, $state) {

        Auth.$onAuth(check);

        $rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) {

            if (error === 'AUTH_REQUIRED') {
                $state.go('home');
            }
            else {
                console.log('authenticated');
            }
        });

        function check(user) {

            if (!user && authRequired($location.path())) {

                $state.go('home');
            }
        }

        function authRequired(path) {
            return SECURED_ROUTES.hasOwnProperty(path);
        }
    }
])
.constant('SECURED_ROUTES', {});

Router

.state('selection', {
    url: '/selection',
    authRequired: true,
    views: {

        'list': {

            templateUrl: 'app/views/project-list.html',
            controller: 'ProjectListCtrl as projectList',
            resolve: {    
              'user': ['Auth', function(Auth) {
                  return Auth.$waitForAuth();
               }]
             }
        },
        'selectionlist': {

            templateUrl: 'app/views/selection-list.html',
            controller: 'SelectionListCtrl as selectionList'
            resolve: {    
              'user': ['Auth', function(Auth) {
                  return Auth.$waitForAuth();
               }]
             }
        }
    }
})

Answer

S.Klechkovski picture S.Klechkovski · Sep 12, 2015

This is a common problem in Single Page Applications. With Angular you can solve it with $http interceptor.

The idea is if the session is expired the first time when the user needs some action from the backend to be redirected to the login page. Expired session is detected from the response itself.

Example:

.factory('httpAuthInterceptor', function ($q) {
  return {
    'responseError': function (response) {
      // NOTE: detect error because of unauthenticated user
      if ([401, 403].indexOf(response.status) >= 0) {
        // redirecting to login page
        $state.go('home');
        return response;
      } else {
        return $q.reject(rejection);
      }
    }
  };
})

.config(function ($httpProvider) {
  $httpProvider.interceptors.push('httpAuthInterceptor');
});