devour-js/devour-client

How to handle refresh Token

Opened this issue · 2 comments

How to handle unauthorized error after main auth token expires and do a refresh token request?

I tried something like this:

import JsonApi from 'devour-client'
import store from '../store/index'

const api = new JsonApi({
    apiUrl: 'http://0.0.0.0:8081/api/v1',
    bearer: null,
  },
)
api.define('token-request', {
  token: '',
  refresh_token: '',
})
const authMiddleware = {
  name: 'refresh-token',
  error: (payload) => {
    if (payload.response) {
      const response = payload.response
      if (response.status === 401) {
        const refreshToken = store.getters['auth/rToken']
        if (!refreshToken) {
          return payload
        }
        api.removeMiddleware('refresh-token')
        console.log('refresh-token', store.getters['auth/rToken'])
        api.runMiddleware({
          url: api.apiUrl + '/auth/refresh-token',
          method: 'POST',
          data: {
            refresh_token: store.getters['auth/rToken'],
          },
          model: 'token-request',
        })
          .then((r) => {
            console.log('worked', r.data.token)
            store.dispatch('auth/refreshToken', r.data)
            // need to retry the request
            return api.axios(payload)
          })
          .catch((err) => {
            console.log('failed', err)
          })
          .finally(() => {
            api.insertMiddlewareBefore('errors', authMiddleware)
          })
      }
    }
    return payload
  },
}
api.insertMiddlewareBefore('errors', authMiddleware)

export default api

the part with api.axios(payload) is not working, I need to retry the last request if everything is OK but I get error

failed TypeError: Cannot read property 'protocol' of undefined
    at isURLSameOrigin (isURLSameOrigin.js?3934:57)
    at dispatchXhrRequest (xhr.js?b50d:109)
    at new Promise (<anonymous>)
    at xhrAdapter (xhr.js?b50d:12)
    at dispatchRequest (dispatchRequest.js?5270:52)

adding a new method works to some level:

import JsonApi from 'devour-client'

const api = new JsonApi({
    apiUrl: 'http://0.0.0.0:8081/api/v1',
    bearer: null,
    errorBuilder: (error) => error,
  },
)
api.authRequest = function (req) {
  return this.runMiddleware(req)
    .catch((err, r) => {
      if (err[0].status === '401') {
        const refreshToken = store.getters['auth/rToken']
        if (!refreshToken) {
          return Promise.reject(err)
        }
        console.log('refresh-token', store.getters['auth/rToken'])
        return api.runMiddleware({
          url: api.apiUrl + '/auth/refresh-token',
          method: 'POST',
          data: {
            refresh_token: store.getters['auth/rToken'],
          },
          model: 'token-request',
        })
          .then((r) => {
            console.log('worked', r.data.token)
            store.dispatch('auth/refreshToken', r.data)
            return this.runMiddleware(req)
          })
          .catch((e) => {
            console.log('failed', e)
            return Promise.reject(err)
          })
      }
    })
}

but if the request fails again somehow I end up with both an error and a result.

ah nevermind that actually worked it was just having then after catch in the first call.

Anyways, can you confirm if this solution is correct?