Session management is a critical part of web application security and performance. It ensures that users have a consistent experience while interacting with your AngularJS application, especially when dealing with sensitive data and authentication. Effective session management helps protect user information, reduce the risk of unauthorized access, and improve the overall performance of the application.
In AngularJS, managing sessions typically involves handling user authentication, storing session data, maintaining the user’s state across different views, and managing token expiration. Below are some best practices to follow for session management in AngularJS applications.
1. Use Token-Based Authentication (JWT)
One of the most common and secure ways to manage sessions in modern web applications is through JSON Web Tokens (JWT). JWT is a compact and secure method of transmitting information between the client and the server as a JSON object. It’s widely used in AngularJS applications for managing sessions.
Steps to Implement JWT:
- Generate Token on the Server: When the user logs in, the server should generate a JWT token and send it to the client.
- Store Token on the Client Side: Store the JWT token in a secure place. Avoid using local storage for storing sensitive tokens, as it’s accessible to any JavaScript code. Prefer HTTP-only cookies for security reasons.
- Send Token with Each Request: Attach the JWT token to the HTTP request headers to authenticate the user for subsequent requests.
Example:
// AngularJS service for handling authentication
angular.module('app').service('AuthService', function($http, $cookies) {
this.login = function(credentials) {
return $http.post('/api/login', credentials)
.then(function(response) {
// Store the token in a secure HTTP-only cookie
$cookies.put('auth_token', response.data.token);
});
};
this.getToken = function() {
return $cookies.get('auth_token');
};
this.logout = function() {
// Remove the token upon logout
$cookies.remove('auth_token');
};
});
2. Use Secure, HTTP-Only Cookies
Avoid storing authentication tokens in local storage or session storage as they can be easily accessed by malicious JavaScript code, putting your app at risk of Cross-Site Scripting (XSS) attacks. HTTP-only cookies are a better choice as they are not accessible via JavaScript, making it harder for attackers to hijack the session.
How to Store Tokens in Cookies:
You can use AngularJS’s $cookies
service to manage cookies securely.
angular.module('app').config(function($cookiesProvider) {
// Use secure, HTTP-only cookies for token storage
$cookiesProvider.defaults.secure = true;
$cookiesProvider.defaults.httpOnly = true;
});
Make sure the cookies are set with the Secure
flag, meaning they will only be sent over HTTPS connections.
3. Token Expiry Handling
Token expiration is an essential part of session management. A token usually has a set expiration time (e.g., 1 hour), after which it should be invalidated. When the token expires, the user should be logged out and required to authenticate again.
Managing Token Expiry:
- On the client-side, you can check for token expiration and refresh it if needed before making requests.
- On the server-side, ensure that expired tokens are rejected, and you provide an endpoint to refresh the token if the session is still valid.
Example:
You can create an Interceptor
in AngularJS to attach the token to requests and handle token expiration:
angular.module('app').factory('AuthInterceptor', function($q, $cookies, $location) {
return {
request: function(config) {
var token = $cookies.get('auth_token');
if (token) {
config.headers['Authorization'] = 'Bearer ' + token;
}
return config;
},
responseError: function(rejection) {
if (rejection.status === 401) {
// Token expired or invalid, logout and redirect to login
$cookies.remove('auth_token');
$location.path('/login');
}
return $q.reject(rejection);
}
};
});
angular.module('app').config(function($httpProvider) {
$httpProvider.interceptors.push('AuthInterceptor');
});
4. Handle User Session Timeout
Session timeouts are essential for protecting sensitive data, especially in case users leave their sessions unattended. Implement an automatic session timeout feature that logs the user out after a specified period of inactivity.
Steps to Implement Session Timeout:
- Track User Activity: Use
$timeout
to detect user activity (mouse movements, keypresses, etc.). - Logout After Inactivity: If no activity is detected after a certain period, automatically log out the user.
- Show Warning Before Expiry: You can display a warning message to the user about session expiration and give them the option to extend the session.
angular.module('app').run(function($rootScope, $timeout, AuthService) {
var idleTime = 0;
var idleInterval = $timeout(function() {
idleTime++;
if (idleTime > 15) { // logout after 15 minutes of inactivity
AuthService.logout();
$location.path('/login');
}
}, 60000); // check every minute
$rootScope.$on('userActivity', function() {
idleTime = 0;
});
// Listen for user activity and reset idle time
document.onmousemove = document.onkeypress = function() {
$rootScope.$emit('userActivity');
};
});
5. Protect Routes Using Guards
AngularJS does not have built-in route guards like Angular 2+, but you can create custom route guards by checking whether the user is authenticated before navigating to a restricted route.
Steps for Route Guards:
- Check if User is Authenticated: Before allowing navigation to a route, check if the user is logged in (i.e., if the authentication token exists).
- Redirect to Login if Unauthorized: If the user is not authenticated, redirect them to the login page.
Example:
angular.module('app').config(function($routeProvider) {
$routeProvider
.when('/profile', {
templateUrl: 'profile.html',
controller: 'ProfileController',
resolve: {
auth: function(AuthService, $location) {
if (!AuthService.getToken()) {
$location.path('/login');
}
}
}
});
});
In this example, the resolve
property ensures that the user is authenticated before accessing the /profile
route. If not, they are redirected to the login page.
6. Use Session Storage for Non-Sensitive Data
For less sensitive data (e.g., user preferences, UI state), you can use sessionStorage or localStorage. These provide simple and effective ways to store data across sessions or page reloads. However, be cautious when storing sensitive data like authentication tokens.
// Store non-sensitive data in sessionStorage
sessionStorage.setItem('userPreference', 'darkMode');
// Retrieve data
var userPreference = sessionStorage.getItem('userPreference');
7. Implement Session Persistence
For a better user experience, you might want to keep the user logged in across page reloads, even if the session expires. This can be done by storing the authentication token in a secure cookie or localStorage, and automatically logging the user in when the page reloads.
angular.module('app').run(function($rootScope, AuthService, $location) {
var token = localStorage.getItem('auth_token');
if (token) {
AuthService.setToken(token); // Automatically log the user in
} else {
$location.path('/login');
}
});
8. Secure User Logout
Ensure that users can securely log out, which involves:
- Clearing All Session Data: Remove any session data, including authentication tokens and user data from the client.
- Invalidate Session on Server: Optionally, you can also invalidate the session on the server-side to further reduce the chances of session hijacking.
angular.module('app').service('AuthService', function($cookies, $http) {
this.logout = function() {
// Clear the token from the cookies and localStorage
$cookies.remove('auth_token');
localStorage.removeItem('auth_token');
// Optionally, make a request to invalidate the session on the server
$http.post('/api/logout');
};
});