Как сделать отправление refresh токена только на запрос от refresh cookie

Ответ

Для этого можно использовать флаг httpOnly и secure для refresh токена в куках, чтобы он не был доступен через JavaScript. При этом access токен отправляется в заголовке запроса.

Пример реализации на Express.js:

// Установка refresh токена в куки
res.cookie('refreshToken', refreshToken, {
  httpOnly: true,
  secure: true, // Только для HTTPS
  sameSite: 'strict', // Защита от CSRF
  maxAge: 30 * 24 * 60 * 60 * 1000 // 30 дней
});

// Проверка refresh токена из куки при запросе на /refresh
app.post('/refresh', (req, res) => {
  const refreshToken = req.cookies.refreshToken;
  if (!refreshToken) return res.sendStatus(401);

  // Проверка токена и выдача нового access токена
  jwt.verify(refreshToken, process.env.REFRESH_SECRET, (err, user) => {
    if (err) return res.sendStatus(403);
    const newAccessToken = generateAccessToken(user);
    res.json({ accessToken: newAccessToken });
  });
});

Таким образом, refresh токен доступен только серверу через куки, а клиент получает новый access токен в ответе.

Ответ 18+ 🔞

А, слушай, вот смотри, как эту токенную махинацию наладить, чтобы не было как обычно — пиздец и всё украли. Ты ж знаешь, эти фронтендеры вечно лезут куда не просят, localStorage шарить, а потом орут «ой, токены упёрли!».

Так вот, блядь, refresh токен надо в куки пихать, но не абы как, а с умом. Ставишь ему флаги httpOnly и secure, чтобы эта мартышлюшка JavaScript до него дотянуться не могла. А access токен кидаешь в заголовке запроса, как порядочные люди.

Смотри, как на Express.js это выглядит, ёпта:

// Установка refresh токена в куки
res.cookie('refreshToken', refreshToken, {
  httpOnly: true,
  secure: true, // Только для HTTPS
  sameSite: 'strict', // Защита от CSRF
  maxAge: 30 * 24 * 60 * 60 * 1000 // 30 дней
});

// Проверка refresh токена из куки при запросе на /refresh
app.post('/refresh', (req, res) => {
  const refreshToken = req.cookies.refreshToken;
  if (!refreshToken) return res.sendStatus(401);

  // Проверка токена и выдача нового access токена
  jwt.verify(refreshToken, process.env.REFRESH_SECRET, (err, user) => {
    if (err) return res.sendStatus(403);
    const newAccessToken = generateAccessToken(user);
    res.json({ accessToken: newAccessToken });
  });
});

Вот и вся магия, блядь. Refresh токен сидит в куках, как в танке — недоступный, зашифрованный, и только сервер к нему лапу приложит, когда надо новый access токен выписать. А клиент получает свеженький access токен в ответе и радуется, как дурак. И никаких тебе дыр, всё по фэншую, в рот меня чих-пых!