mlegenhausen / fetch-intercept

Interceptor library for the native fetch command inspired by angular http intercepts.
MIT License
406 stars 52 forks source link

Handling refresh token by recall same request after refreshing the token #39

Open MhamedRamadan10 opened 5 years ago

MhamedRamadan10 commented 5 years ago

Hi, I am trying to make a common interceptor to authorize all my outgoing requests.

My logic is as follows:

All my outgoing requests/API calls passes through the interceptor first to check on my token expiry and in-case the response was un-authorized I make an internal call to refresh the token and update my storage keys with the new values.

Now I need to recall the original request with the new token value, but I can't figure out how to detect the original request that passed through the interceptor.

This is my code :

export  const unregister =  fetchIntercept.register({
  request: function (url, config) {
    return [url, config];
  },

  requestError: function (error) {
    return Promise.reject(error);
  },
  responseError: function (error) {
    return Promise.reject(error);
  },

  response: function (response) {
    if (response.status == 401) {
      Services.refreshToken((res)=>{
        if (res.message == 'success') {
          // if token has been refreshed
          // recall the request again
        }else {
          // login again
        }
      })
    }else {
      return response;
    }
  }
})

The problem is that I've no idea how to recall the same request that passed through the interceptor.. I did some search on this, but couldn't find a way to execute this.

ChristianUlbrich commented 5 years ago

You are on the right track; I built something similar two years ago. You just have to store the failed request somewhere and simply redispatch it; for this you must correlate the errors with the actual requests made; in the original Angular interceptor stuff, you could get the config of the original request and thus re-construct the actual request.

lukaszkostrzewa commented 4 years ago

How about instead of retrying when there is 401 HTTP status, simply check earlier (in request interceptor) if token is expired or not? And if it's expired, then refresh the token?

AnkitaPatelST commented 4 years ago

Hi, I am trying to make a common interceptor to authorize all my outgoing requests.

My logic is as follows:

All my outgoing requests/API calls passes through the interceptor first to check on my token expiry and in-case the response was un-authorized I make an internal call to refresh the token and update my storage keys with the new values.

Now I need to recall the original request with the new token value, but I can't figure out how to detect the original request that passed through the interceptor.

This is my code :

export  const unregister =  fetchIntercept.register({
  request: function (url, config) {
    return [url, config];
  },

  requestError: function (error) {
    return Promise.reject(error);
  },
  responseError: function (error) {
    return Promise.reject(error);
  },

  response: function (response) {
    if (response.status == 401) {
      Services.refreshToken((res)=>{
        if (res.message == 'success') {
          // if token has been refreshed
          // recall the request again
        }else {
          // login again
        }
      })
    }else {
      return response;
    }
  }
})

The problem is that I've no idea how to recall the same request that passed through the interceptor.. I did some search on this, but couldn't find a way to execute this.

Did find the solution? because I have the same issue

sai30 commented 4 years ago

I am having the same issue. Not sure how to recall the failed request after refreshing token. Is there any solution for this?

TheArKaID commented 3 years ago

How if, we intercept in the request, store the url in the storage, and then use the stored url after the refresh token used to get access token ?

awaissahmed80 commented 3 years ago

Here is example of refresh token and recall the original request

const originalRequest = {}
export const interceptor = fetchIntercept.register({    
    request: function (url, config) {
        originalRequest.url = url
        originalRequest.config = config
        return [url, config];
    },

    requestError: function (error) {
        // Called when an error occured during another 'request' interceptor call        
        return Promise.reject(error);
    },

    response: async function (response) {
        if(response.status === 401)
        {
            const {url, config} = originalRequest
            if(url.includes('token'))
            {
                interceptor()
                return Promise.reject("Session expired");
            }
            else
            {                
                return AppStore.dispatch(AuthActions.refresh_token())
                        .then((data) => {
                            config['headers']['Authorization'] = 'Bearer '+data.token
                            return fetch(url, config)
                        })
                        .catch((error) => {
                            return Promise.reject(error)
                        })                            
            }            
        }
        else
        {
            return response
        }        
    },

    responseError: function (error) {
        // Handle an fetch error
        return Promise.reject(error);
    }
});
vitorcamachoo commented 3 years ago

Here is example of refresh token and recall the original request

const originalRequest = {}
export const interceptor = fetchIntercept.register({    
    request: function (url, config) {
        originalRequest.url = url
        originalRequest.config = config
        return [url, config];
    },

    requestError: function (error) {
        // Called when an error occured during another 'request' interceptor call        
        return Promise.reject(error);
    },

    response: async function (response) {
        if(response.status === 401)
        {
            const {url, config} = originalRequest
            if(url.includes('token'))
            {
                interceptor()
                return Promise.reject("Session expired");
            }
            else
            {                
                return AppStore.dispatch(AuthActions.refresh_token())
                        .then((data) => {
                            config['headers']['Authorization'] = 'Bearer '+data.token
                            return fetch(url, config)
                        })
                        .catch((error) => {
                            return Promise.reject(error)
                        })                            
            }            
        }
        else
        {
            return response
        }        
    },

    responseError: function (error) {
        // Handle an fetch error
        return Promise.reject(error);
    }
});

This will not work if multiple requests were made in parallel. It will use the wrong url and config