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();
}]
}
}
}
})
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');
});