An Angular app using JWT for API authetication launchs a login dialog when a call to the API returns 401 "Unauthorized"
, to let the user input his credentials and get a new valid JWT. Then the app retries the failed unauthorized request and keeps the flow.
The code listed here is based in this solution by Chris Clarke.
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(['$q', '$location', '$injector', function ($q, $location, $injector) {
return {
'responseError': function(response) {
// Keep the response waiting until we get new JWT
var deferred = $q.defer();
if (response.status === 401 && response.data.error && response.data.error.message.toLowerCase() === "unauthorized") {
// JWT has expired
// Open login dialog
var cslAuth = $injector.get('cslAuth');
if (cslAuth.isLoggedIn()) {
// Logout user, next pending request will not trigger auth dialog
cslAuth.logout();
$injector.get('ngDialog').openConfirm({
template: 'web_app/views/login.html',
className: 'ngdialog-theme-default',
showClose: false,
controller: 'LoginCtrl',
cache: false
})
.then(
function(value) {
// JWT has been refreshed. Try pending request again
var config = response.config;
// Inject the new token in the Auth header
config.headers.Authentication = cslAuth.getTokenHeader();
$injector.get("$http")(config).then(
function(response){
deferred.resolve(response);
},
function(response) {
deferred.reject();
}
);
},
function(value) {
deferred.reject();
}
);
}
} else {
return $q.reject(response);
}
// Return a promise while waiting for auth refresh
return deferred.promise;
}
}
}])
}])
The problem is when there are more than one request going with the expired token. The first one comming back should trigger the login dialog and get the new token. But how make the other pending requests wait until the new token is available? A flag could be set to tell all following incoming responses that a new token is being requested. A promise can be returned and all config objects can be stored in an array in a Service. When the new token is available all waiting requests could be retried. But what happen with unauthorized requests returning after the new token is available? They will trigger a new login dialog.
Some notes an extras:
This answer gives a solution to a related problem, but since there is a new login involved here I can not see how to adapt the solution to this case.
It's not an option to autorenew the token. Tokens will have 8 hours expiration (a working session) and new login is mandatory.
- Is it safe to inject services (
cslAuth
and$http
here) in a config object? My code is working but I have read they can not be fully ready at this point.