Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to refresh data after refresh token refreshes jwt

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:

enter image description here

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!

like image 427
RandomUs1r Avatar asked May 12 '17 21:05

RandomUs1r


People also ask

How do you handle a refresh JWT token?

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.

Can you refresh a refresh token?

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.

What if refresh token expired?

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.

How do you refresh a JWT token in Python?

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.


2 Answers

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.

like image 123
Prateek Gupta Avatar answered Oct 22 '22 06:10

Prateek Gupta


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.

like image 26
Jon Black Avatar answered Oct 22 '22 04:10

Jon Black