question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. ItĀ collects links to all the places you might be looking at while hunting down a tough bug.

And, if youā€™re still stuck at the end, weā€™re happy to hop on a call to see how we can help out.

The request does not return to its original promise and instance is not paused until refresh is complete

See original GitHub issue

I was using this library with its previous versions (worked great by the way šŸ‘ ) but I decided to update axiosā€™s and its version because I was facing other problems. But now there is the problem that failed request due to 401 or 403 does not return to its original promise it just fires again and resolves.

Here is my logic for calling apis:

const refreshAuthLogic = (failedRequest) =>
  axios
    .post(`${process.env.API_BASE_URL}user/refresh/`, getFormData())
    .then((tokenRefreshResponse) => {
      console.log(tokenRefreshResponse.data.refresh_token)
      Cookies.set('token', tokenRefreshResponse.data.access_token, {
        expires: 1 / 24
      })
      Cookies.set('refreshToken', tokenRefreshResponse.data.refresh_token, {
        expires: 365
      })
      failedRequest.response.config.headers.Authorization = `Bearer ${
        tokenRefreshResponse.data.access_token
      }`
      return Promise.resolve()
    })
    .catch((error) => {
      // if(Cookies.get('refreshToken') == undefined && Cookies.get('token')) {
      Auth.signout()
      window.location.reload(false)
      // }
    })

const instance = axios.create({
  baseURL: process.env.API_BASE_URL
})
instance.interceptors.request.use((request) => {
  request.headers.Authorization = `Bearer ${Cookies.get('token')}`
  return request
})
createAuthRefreshInterceptor(instance, refreshAuthLogic, {
  statusCodes: [401, 403],
  pauseInstanceWhileRefreshing: true
})
export default instance

and I use the instance like:

const settingsPromise = API.get('user/settings/', {
      headers: { Authorization: `Bearer ${Cookies.get('token')}` }
    })

    const userDataPromise = API.get('user/profile/', {
      headers: { Authorization: `Bearer ${Cookies.get('token')}` }
    })

    Promise.all([settingsPromise, userDataPromise]).then((result) => {
      // other code
    })

and sometimes:

API.get('user/settings/', {
      headers: { Authorization: `Bearer ${Cookies.get('token')}` }
    }).then((result) => {
      // other code
    })

but for these calls it does not return to promise.

Also the instance is not paused until refresh is complete, even after refresh is called more requests are made and they also return 401 or 403 and there is another refresh call.

axios@0.21.1 axios-auth-refresh@3.1.0

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:10
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
amcsicommented, Mar 29, 2021

Iā€™m also getting the same issue. Though I happened to come across a fairly simple workaround:

before:

createAuthRefreshInterceptor(
  api,
  error => {
    // Maybe the token just expired and we need to refresh it. Let's try that.
    return api
      .post('/refreshEndpoint', {refresh_token: refreshToken})
      .then(response => {
        // some success logic...
        return Promise.resolve();
      })
      .catch(() => {
        // some failure logic...
        return Promise.reject(error);
      });
  },
  // The following option doesn't seem to work.
  { pauseInstanceWhileRefreshing: true }

after (see

// Addition 1/3.
let refreshingPromise = null;

createAuthRefreshInterceptor(
  api,
  error => {
    // Addition 2/3.
    if (refreshingPromise) {
      return refreshingPromise;
    }

    // Maybe the token just expired and we need to refresh it. Let's try that.
    return api
      .post('/refreshEndpoint', {refresh_token: refreshToken})
      .then(response => {
        // some success logic...
        return Promise.resolve();
      })
      .catch(() => {
        // some failure logic...
        return Promise.reject(error);
      })
      // Addition 3/3.
      .finally(() => {
        // Clear the promise so that newer calls to this interceptor would initiate a fresh API call.
        refreshingPromise = null;
      });
  },
  // The following option doesn't seem to work.
  { pauseInstanceWhileRefreshing: true }
0reactions
ammarrushcommented, Nov 29, 2021

I tried what you said @Flyrell, it returns to the original promise now but the refresh logic is being run twice for three consecutive api calls. Also, I donā€™t think I need skipAuthRefresh flag because I actually donā€™t use the instance to call the api in refresh logic. I tried using instance in the refresh logic with skipAuthRefresh and that also didnā€™t work.

I changed my code a bit so here it is for reference:

const refreshAuthLogic = (failedRequest) =>
  axios.post(
    env_variables.url+'user/refresh/',
    getFormData()
  ).then((result)=>{
    logAmplitude('Token Refresh successful')
    localStorage.setItem("token", result.data.access_token);
    localStorage.setItem("refreshToken", result.data.refresh_token);
    failedRequest.response.config.headers['Authorization'] = 'Bearer ' + result.data.access_token;
    return Promise.resolve();
  })
  .catch((error)=>{
    logAmplitude('Token Refresh failed')
            
    const refreshTokVal = localStorage.getItem('refreshToken')
    ? localStorage.getItem('refreshToken')
    : 'No refresh token'
    
    logAmplitude(refreshTokVal)
    Auth.signout();
    window.location.reload(false);
  })

Create auth func:

createAuthRefreshInterceptor(instance, refreshAuthLogic, {
  statusCodes: [401, 403]
});

Example request scenario:

API.get("user/profile/")
      .then((result)=>{
          console.log("ONE SUCCESS")
          console.log(result)
          this.setState({userName: result.data.fullName})
      })

      API.get("user/profile/")
      .then((result)=>{
          console.log("TWO SUCCESS")
          console.log(result)
      })

      API.get("user/profile/")
      .then((result)=>{
          console.log("THREE SUCCESS")
          console.log(result)
    })
  What my network looks like :

image

Read more comments on GitHub >

github_iconTop Results From Across the Web

Wait until all promises complete even if some rejected
I was searching hard for Promise.all not even first reject but didn't know to search "Reflect". Should ES6 have a Promise.reflect which is...
Read more >
Node.js v19.3.0 Documentation
If the function does not return a promise, assert.doesNotReject() will return a rejected Promise with an ERR_INVALID_RETURN_VALUE error. In both cases the errorĀ ......
Read more >
API Reference - Tableau Help
Represents a promise to return a value from an asynchronous method in the future. ... The permissions on a workbook or a view...
Read more >
Refresh an external data connection in Excel - Microsoft Support
You can connect your Excel workbook to an external data source, such as a SQL Server database, an OLAP cube, or even another...
Read more >
Frequently Asked Questions | Republic Services
Through our subsidiaries, we provide recycling and non-hazardous solid waste ... By default, your auto pay will pay the full balance of your...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found