Refresh token without Axios etc

Hi all!

I am trying to solve the problem of updating the access token without using third-party extensions.

All HTTP requests in the application are processed centrally, using a separate action.
If the TokenExpired error came in response to the request, then I send a token update request (access & refresh) and repeat the request again.

The problem is that the application components start sending requests almost simultaneously. The first request sends a refresh token, after which the old tokens on the server are deleted and when a request comes from another component, the server does not find the received tokens and sends a TokenError in response. The application, seeing a message about an incorrect token, redirects the user to the authorization page [application after restarting and not finding the token in localStorage, push to the authorization screen].

Help solve the problems, please. I will be glad of any good advice. Thanks in advance for the answers!

App HTTP request

async readUsers({rootState, state, getters, dispatch}, payload) {

const token = rootState.token.access

if(token) {

    state.usersProcess = true

    let params = ''

    if(payload) {

        for( let param in payload) {

            params.length ?
                params += '&' + param + '=' + payload[param] :
                params = '?' + param + '=' + payload[param]
        }
    }

    const request = await dispatch('fetchRequest', {
        address: `${rootState.config.httpServer}/users${params}`, 
        method: 'GET', 
        token: true
    })

    if(!request.error) {

        state.users = request
        state.usersMsg = { success: true }

    } else {

        state.usersMsg = { success: false }
        state.usersMsg.text = getters.getTranslate[request.error] || request.error
    }

    state.usersProcess = false

} else {

    state.usersMsg = { success: false, text: getters.getTranslate.EUnauthRequest }
}

}

Action for processing app HTTP requests

async fetchRequest({rootState, dispatch}, payload) {

let parameters = {

    method: payload.method,
    cache: 'no-cache',
    referrerPolicy: 'origin-when-cross-origin',
    headers: new Headers()
}

if(payload.token) {

    parameters.headers.append('Authorization', 'Bearer ' + rootState.token.access)
} 

if(payload.data) {

    if(payload.type) {

        payload.type == 'json' ?
            parameters.body = JSON.stringify(payload.data) :
            parameters.body = payload.data

    } else {

        parameters.body = JSON.stringify(payload.data)
    }
}

try {

    const request = await fetch(payload.address, parameters)

    const response = await request.text()

    const result = JSON.parse( response )

    if(request.ok) {

        return result

    } else if(result.details) {

        if(result.details == 'TokenExpired') {

            dispatch('refreshToken').then(() => {

                if(rootState.token.access) {

                    dispatch('fetchRequest', payload)
                }
            })

        } else if(result.details == 'TokenError') {

            localStorage.clear()
            document.location.reload()
        }

        return { error: result.details }

    } else if(result.message) {

        return { error: result.message }

    } else {

        return { error: 'EUnknown' }
    }

} catch {

    return { error: 'EConnection' }
}

}

Refresh token action

async refreshToken({rootState, state, dispatch}) {

const request = await dispatch('fetchRequest', {
    address: `${rootState.config.httpServer}/refresh_tokens`, 
    method: 'POST', 
    data: `"${rootState.token.refresh}"`,
    type: 'string'
})

if(request.tokens) {

    state.access = request.tokens.access
    state.refresh = request.tokens.refresh

    localStorage.setItem('TOKEN_ACCESS', state.access)
    localStorage.setItem('TOKEN_REFRESH', state.refresh)

} else {

    state.access = null
    state.refresh = null

    localStorage.removeItem('TOKEN_ACCESS')
    localStorage.removeItem('TOKEN_REFRESH')
}

}

Completely confused with asynchronous requests :hot_face:

...
if(rootState.token.access) {

    dispatch('fetchRequest', payload)
}
...

Забыл сделать return:

...
if(rootState.token.access) {

    return dispatch('fetchRequest', payload)
}
...