Не получается обновить accessToken

Пишу свой проект, с целью изучения фронтенда (поэтому много говнокода, за советы также буду благодарен)

Пытаюсь получить доступ к всем данным пользователей по запросу api.get('/users')

const getUsers = (req, res, next) => {
    const db = low(adapter)

    const result = authMiddleware(req, res) // Я пробовал запихнуть его как middleware, но почему-то происходит бесконечная попытка отправить запрос, посмотрю позже

    if (result === 401) { return res.sendStatus(401) }

    let DB = db.get('users').value()
    res.json(DB)

    return
}


// authMiddleware - src/middleware/auth


const jwt = require('jsonwebtoken');
const { access_secret, refresh_secret, tokens } = require('../config/config').config
const { validateAccessToken } = require('../service/token')


const authMiddleware = (req, res) => {

    const authHeader = req.headers.authorization
    if (!authHeader) { return 401 }

    const accessToken = authHeader.split(' ')[1]
    if (!accessToken) { return 401 }

    const tokenData = validateAccessToken(accessToken) // Возвращает null так как токен сдох, но мы же его обновили?
    if (!tokenData) { return 401 }

    req.user = tokenData
    return req
}

module.exports = { authMiddleware }

Проблема:

При истечении срока жизни accessToken я отправляю запрос на обновление пары токенов. Отслеживаю с помощью кастомного axios'а

// src/http/axios
import axios from 'axios'



const api = axios.create({
    withCredentials: true,
})

api.interceptors.request.use((config) => {
    config.headers.common['Authorization'] = `Bearer ${localStorage.getItem('token')}`
    return config
})

api.interceptors.response.use((config) => {
    return config
}, async (error) => {
    const originalRequest = error.config

    if (error.response.status === 401) {
        try {
            const response = await api.post('/api/refresh', {withCredentials: true})

            localStorage.setItem('token', response.data.accessToken)
            return api.request(originalRequest)
        } catch (error) {
            console.error(error)
        }
   }
})

export default api

При попытке обновить токен, данный код входит в цикл, так как почему-то токен не обновился и он все еще не рабочий

Посмотрел, что дает api.post, он возвращает сначала несколько раз старый токен, а потом новый, и все повторяется

На стороне сервера:

const refresh = (req, res) => {
    const { refreshToken } = req.cookies

    const result = refreshThisToken(refreshToken)

    if (result === 401) {
        res.sendStatus(401)
    } else {
        res.cookie('refreshToken', result.refreshToken, { httpOnly: true, maxAge: 1000 * 60 * 5 }).json(result).send()
        return

    }
    res.send()
}

На стороне сервиса по обновлению refreshToken'а

const refreshThisToken = (refreshToken) => {
    const db = low(adapter)

    if (!refreshToken) {
        return 401
    }

    const tokenData = validateRefreshToken(refreshToken)
    const getToken = db.get('users').find({ refreshToken: refreshToken }).value()

    if (!tokenData || !getToken) {
        return 401
    }
    const user_data = {
        userMail: getToken.userMail,
        userLogin: getToken.userLogin,
        userName: getToken.userData.userName,
        contacts: getToken.userData.contacts,
        url: getToken.userData.url
    }

    const tokens = generateTokens(user_data)
    saveToken(user_data.userLogin, tokens.refreshToken)

    return tokens
}

Здесь должно быть все хорошо, проходит все без 401, это и видно в браузере по запросам, но запрос к get /users возвращает 401, тк validateAccessToken вернул 401

Глаза уже замылились, не вижу, что я упустил

Всем спасибо!


Ответы (1 шт):

Автор решения: Семён Голган

Я совершенно смотрел не туда, оказывается в originalRequest параметр headers.Authorization токен не менялся и код входил в цикл) Мне просто нужно было обновить его, думал этим занимается верхний интерцептор, доставая токен из localStorage, но оказалось все иначе!

Правильный код:

// src/http/axios
import axios from 'axios'



const api = axios.create({
    withCredentials: true,
})

api.interceptors.request.use((config) => {
    config.headers.common['Authorization'] = `Bearer ${localStorage.getItem('token')}`
    return config
})

api.interceptors.response.use((config) => {
    return config
}, async (error) => {
    const originalRequest = error.config

    if (error.response.status === 401) {
        try {
            const response = await api.post('/api/refresh', {withCredentials: true})
            originalRequest.headers.Authorization = `Bearer ${response.data.accessToken}` // New!

            localStorage.setItem('token', response.data.accessToken)
            return api.request(originalRequest)
        } catch (error) {
            console.error(error)
        }
   }
})

export default api
→ Ссылка