0

I have auth with axios and interceptors and I am having issue with the user logout.

When a accessToken is invalidated I am calling revalidate with a refreshToken. When is even the refreshToken invalid I want to logout a user, but I am not sure how to stop/clear all requests which are triggered in the app by useSWR with axios fetcher.

What is the best practice to do this?

const initAxios = onAuthFinish => {
  axios.interceptors.request.use(
    config => {
      const accessToken = Cookies.get(authKeys.accessToken)
      const tokenType = Cookies.get(authKeys.tokehType)
      if (accessToken) {
        config.headers.Authorization = `${tokenType} ${accessToken}`
      }
      return config
    }
  )

  let isRefreshing = false
  const refreshSubscribers = []

  const subscribeTokenRefresh = (resolve, reject) => {
    refreshSubscribers.push({resolve, reject})
  }

  const onRrefreshed = token => {
    while (refreshSubscribers.length > 0) {
      const {resolve} = refreshSubscribers.pop()
      resolve(token)
    }
  }

  const onExpired = () => {
    while (refreshSubscribers.length > 0) {
      const {reject} = refreshSubscribers.pop()
      reject()
    }
  }

  axios.interceptors.response.use(
    response => response,
    error => {
      const originalRequest = error.config

      if (error.response.status === 403) {
        // refresh token is invalid - WHAT TO DO HERE?
        removeAuthData()
        onAuthFinish()
        return Promise.reject(error)
      }

      if (error.response.status === 401) {
        if (!isRefreshing) {
          isRefreshing = true
          userApi.refreshLogin(Cookies.get(authKeys.refreshToken)).then(res => {
            isRefreshing = false
            if (res && res.data) {
              setAuthData(res.data)
              const newToken = `${Cookies.get(authKeys.tokehType)} ${Cookies.get(authKeys.accessToken)}`
              axios.defaults.headers.common.Authorization = newToken
              onRrefreshed(newToken)
            }
          }).catch(err => {
            isRefreshing = false
            onExpired()
            // this is caused by reject in 403 status if block - WHAT TO DO HERE?
          })
        }

        const retryOrigReq = new Promise((resolve, reject) => {
          subscribeTokenRefresh(token => {
            originalRequest.headers.Authorization = token
            resolve(axios(originalRequest))
          }, () => {
            originalRequest._retry = false
            reject(axios(originalRequest))
          })
        })
        return retryOrigReq
      }

      return Promise.reject(error)
    },
  )
} 

Currently, I am calling reject on all triggered requests with onExpired - but this still caches all requests so after users re-login there are still previous data. If I do not reject that request it stuck in the loading.

I have also tried to call cache.clear() from import {cache} from 'swr'

Dawe
  • 562
  • 1
  • 9
  • 19
  • How about conditional rendering? https://swr.vercel.app/docs/conditional-fetching If the token is invalid, stop sending requests. – keremistan May 05 '21 at 08:32
  • Then I would need to handle it in each useSWR. I would like to do it ideally in one place to prevent the possibility that someone could forget to add it everywhere – Dawe May 05 '21 at 10:28
  • well, then encapsulate that logic into a function or a hook. – keremistan May 05 '21 at 15:38

1 Answers1

0

It seems that the best solution is just to clear cookies and call redirect:

    removeAuthData()
    window.location.href = '/login/' 
Dawe
  • 562
  • 1
  • 9
  • 19