Handling authentication tokens in API calls

Loading

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 OptionSecurityUse Case
localStorage Not SecurePersist token after page refresh (vulnerable to XSS)
sessionStorage More SecureToken expires when the session ends
Cookies (HttpOnly) Most SecurePrevents XSS but vulnerable to CSRF
Memory (JS variable) Most SecureBest 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);
});

Leave a Reply

Your email address will not be published. Required fields are marked *