I've been trying to get my refresh token to work for a while now, and I hope I'm close. My token refreshes and triggers a subsequent 200 call to whatever call caused the 401, but my the data on my page doesn't refresh.
When an access token expires, the following happens:
After the 401, the GetListofCompanyNames returns 200 with a list of names using the correct updated access token. However, my dropdown does not refresh.
My interceptor:
app.factory('authInterceptorService',['$q', '$location', 'localStorageService', '$injector', function($q, $location, localStorageService, $injector) {
return {
request: function(config) {
config.headers = config.headers || {};
var authData = localStorageService.get('authorizationData');
if (authData) {
config.headers.Authorization = 'Bearer ' + authData.token;
}
return config;
},
responseError: function(rejection) {
//var promise = $q.reject(rejection);
var authService = $injector.get('authService');
if (rejection.status === 401) {
// refresh the token
authService.refreshToken().then(function() {
// retry the request
var $http = $injector.get('$http');
return $http(rejection.config);
});
}
if (rejection.status === 400) {
authService.logOut();
$location.path('/login');
}
return $q.reject(rejection);
}
};
}
]);
My return statement on the 401 rejection looks suspect here, but I'm not sure what to replace it with. Thereby my question is: How can I get my page to refresh it's data when I make the new call?
Update:
This gets me past when the 200 returns and I can get a dropdown to refresh, but I lose any state on the page (ex. selected dropdown) with the below.
authService.refreshToken().then(function() {
var $state = $injector.get('$state');
$state.reload();
});
Back to the drawing board!
We'll first create an express app and then implement two routes login & refresh. The login route will get a post request, then it will check the credentials if they match it'll send a refresh token and access token in response.
You cannot refresh a Refresh Token if the Refresh Token has expired or otherwise been revoked. You must repeat the authentication flow to obtain a new Refresh Token.
When an access token expires, a refresh token is used to get a new access token and it also returns a new refresh token. Now if this new access token expires & a new/updated refresh token is used to get the next access token, it will also receive a newer refresh token.
The client can parse expire time of access token. If access token is expired then you have to request new access token with refresh token according to your algorithm. This is a simple reference source.
Try putting up your retry call in $timeout
, it should work.
Here's the updated code:
app.factory('authInterceptorService',['$q', '$location', 'localStorageService', '$injector', function($q, $location, localStorageService, $injector) {
return {
request: function(config) {
config.headers = config.headers || {};
var authData = localStorageService.get('authorizationData');
if (authData) {
config.headers.Authorization = 'Bearer ' + authData.token;
}
return config;
},
responseError: function(rejection) {
//var promise = $q.reject(rejection);
var authService = $injector.get('authService');
if (rejection.status === 401) {
// refresh the token
authService.refreshToken().then(function() {
// retry the request
return $timeout(function() {
var $http = $injector.get('$http');
return $http(rejection.config);
}});
}
if (rejection.status === 400) {
authService.logOut();
$location.path('/login');
}
return $q.reject(rejection);
}
};
}
]);
$timeout returns a promise that is completed with what is returned from the function parameter, so we can conveniently just return the $http call wrapped in $timeout.
Thanks.
I think you may want to change up how you go about this. One way to go about this would be to inject the $rootScope into your authInterceptorService
and then once you successfully refresh the token, call something like $rootScope.broadcast('tokenRefreshed')
.
I don't quite know how you have set up the view and controller that handles your dropdown, but I would set up a listener for that 'tokenRefreshed'
event. From here, you can do another call to GetListofCompanyNames
. If you do it this way you can easily control and ensure that the model gets updated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With