Authentication tokens (such as JWT) are commonly used to secure API calls. In AngularJS, we can manage tokens efficiently by intercepting HTTP requests and responses. Below are the best practices for handling authentication tokens in AngularJS.
1. Storing Authentication Tokens Securely
Authentication tokens must be stored securely to prevent XSS (Cross-Site Scripting) attacks.
Where to Store Tokens?
Storage Option | Security | Use Case |
---|---|---|
localStorage | Not Secure | Persist token after page refresh (vulnerable to XSS) |
sessionStorage | More Secure | Token expires when the session ends |
Cookies (HttpOnly) | Most Secure | Prevents XSS but vulnerable to CSRF |
Memory (JS variable) | Most Secure | Best for short-lived tokens (cleared on refresh) |
Storing Token Example (localStorage)
localStorage.setItem('authToken', token);
Retrieving Token
var token = localStorage.getItem('authToken');
Removing Token (Logout)
localStorage.removeItem('authToken');
Tip: Use HttpOnly Cookies
for maximum security.
2. Attaching Token to API Requests
Instead of manually adding the token to every request, use an $httpInterceptor
to attach it automatically.
Interceptor to Add Token in Headers
myApp.factory('AuthInterceptor', function($q, $window) {
return {
request: function(config) {
var token = localStorage.getItem('authToken');
if (token) {
config.headers.Authorization = 'Bearer ' + token;
}
return config;
}
};
});
myApp.config(function($httpProvider) {
$httpProvider.interceptors.push('AuthInterceptor');
});
Why Use an Interceptor?
✔ Automatically adds Authorization Header to every request.
✔ Reduces redundant manual token management.
3. Handling Expired Tokens & Unauthorized Requests
When a 401 (Unauthorized) response is received, the system should log out the user or refresh the token.
Interceptor for Token Expiry Handling
myApp.factory('AuthErrorInterceptor', function($q, $injector) {
return {
responseError: function(response) {
if (response.status === 401) {
console.warn("Token expired. Logging out...");
localStorage.removeItem('authToken'); // Clear token
var $state = $injector.get('$state');
$state.go('login'); // Redirect to login
}
return $q.reject(response);
}
};
});
myApp.config(function($httpProvider) {
$httpProvider.interceptors.push('AuthErrorInterceptor');
});
Benefits:
✔ Automatically logs out users when the token expires.
✔ Prevents making API calls with invalid tokens.
4. Refreshing Tokens Automatically
Some authentication systems provide a refresh token to get a new access token when the current one expires.
Refreshing Token in Interceptor
myApp.factory('TokenRefreshInterceptor', function($q, $injector, $http) {
return {
responseError: function(response) {
if (response.status === 401) {
var refreshToken = localStorage.getItem('refreshToken');
if (refreshToken) {
return $http.post('/api/auth/refresh', { token: refreshToken })
.then(function(res) {
localStorage.setItem('authToken', res.data.accessToken);
response.config.headers.Authorization = 'Bearer ' + res.data.accessToken;
return $http(response.config);
});
}
}
return $q.reject(response);
}
};
});
myApp.config(function($httpProvider) {
$httpProvider.interceptors.push('TokenRefreshInterceptor');
});
Advantages:
✔ Automatically refreshes expired tokens.
✔ Reduces user frustration due to unexpected logouts.
5. Securely Logging Out Users
Ensure the authentication token is removed from storage on logout.
Logout Function
$scope.logout = function() {
localStorage.removeItem('authToken');
$state.go('login'); // Redirect to login
};
Best Practice: Always revoke the token on the server-side when logging out.
6. Checking Authentication Status
To prevent unauthorized access to protected routes, check if a token exists before allowing navigation.
Service to Check Auth Status
myApp.factory('AuthService', function($window) {
return {
isAuthenticated: function() {
return !!localStorage.getItem('authToken'); // Returns true if token exists
}
};
});
Restricting Routes to Logged-in Users
myApp.run(function($rootScope, $state, AuthService) {
$rootScope.$on('$stateChangeStart', function(event, toState) {
if (toState.authRequired && !AuthService.isAuthenticated()) {
event.preventDefault();
$state.go('login'); // Redirect unauthorized users
}
});
});
Benefits:
✔ Prevents unauthorized access to restricted pages.
✔ Automatically redirects users to login if they are not authenticated.
7. Making Secure API Calls
After setting up token management, API calls automatically include the token.
$http.get('/api/user/profile')
.then(function(response) {
console.log("User Profile:", response.data);
})
.catch(function(error) {
console.error("Error fetching profile:", error);
});