Обновить

Access‑token в переменной, refresh — в HttpOnly‑cookie: безопасная авторизация на Go + Vue 3

Уровень сложностиСредний
Время на прочтение16 мин
Охват и читатели6.2K
Всего голосов 4: ↑4 и ↓0+8
Комментарии8

Комментарии 8

Привет! Кажется если ты уже используешь httponly-куки, то кажется не нужно уже использовать токены, если ты разрабатываешь 1st party приложение.
Токены кажется обычно нужны для 3st party приложений, и там нужно использовать механизмы по типу OAuth2

Вообще имхо jwt нужны только для микросервисной архитектуры чтобы передать информацию типа user_id с подтверждением валидности между теми самыми сервисами. Для обычных приложения вида "фронтэнд + бэкэнд" это избыточно. В некоторых моих проектах клиент вообще не знает своего id (или производных типа profile_id) (он на него вообще не передается ни в каком виде) и все нормально. Естественно, в таких проектах нет p2p взаимодействий, это b2c штуки.

Согласен, что в распределённых системах JWT действительно раскрывается полностью, а для монолита сессионные куки - альтернатива, и каждая команда выбирает свои технологии. Но на практике JWT часто встречается и в фронт + бек, нет хранилища сессий, тот же токен легко отдать мобильному клиенту. Задача статьи - не убедить всех перейти на JWT, а показать безопасную работу с уже выбранной схемой: access не в localStorage, refresh в httponly куках, обработка 401. И ваше мнение о том что клиент не знает своего id, согласен поэтому в claims сложил минимум телефон и тип, потому что payload JWT читается кем угодно - об этом в статье отдельно написано.

Привет! Справедливое замечание: для чистого 1st‑party монолита классическая сессионная httpOnly кука действительно часто достаточно, а OAuth2 реально про third‑party доступ. Статья разбирает другой, не менее частый кейс: SPA + stateless‑бекенд, где команда уже выбрала JWT (нет таблицы сессий, легко масштабироваться горизонтально, одно API для веба и мобилки). И тогда встаёт вопрос, где хранить access‑token, и худший из ответов - localStorage. Статья о том, как реализовать JWT‑схему безопасно: access в памяти, refresh в httponly куках, восстановление сессии, обработка протухшего токена. Можно, конечно, вообще убрать access и остаться в куках - тоже рабочая схема, просто тогда больше внимания нужно уделить CSRF. Так что это просто разбор, если у вас JWT вот как это можно использовать.

  1. Vuex в новых проектах в 2026 году — уже моветон

  2. Как вы решаете проблему нескольких одновременно упавших запросов с 401 из-за протухшего access-токена? По вашей схеме, если мы заходим на страницу, с которой полетит несколько запросов на данные, защищенные авторизацией — каждый пойдет делать запрос на рефреш. С одним refresh-токеном. И у одного из них отвалится по невалидному (использованном) токену. Можно было раскрыть тему Web Locks API

По vuex согласен, pinia более современная рекомендация. Оставил его, потому что механизм (access в памяти + interceptor) переносится на Pinia/React почти без изменений.

По 401 вы правы. В бекенде из статьи это не приводит к разлогину (refresh - stateless JWT и не инвалидируется, все 5 refresh вернули 200), но при ротации с инвалидацией старого токена это была бы гонка с разлогином. Поправить можно попробовать с помощью single‑flight, один летящий refresh промис, все упавшие его ждут, затем повторяются.

После этой правки тот же тест даёт 5×401 дальше 1×refresh и 5×200. Про Web Locks API согласен, single‑flight закрывает гонку внутри вкладки, а для синхронизации между вкладками нужен navigator.locks или BroadcastChannel мне кажется это следующий уровень, достойный отдельной статьи.

Я, конечно, извиняюсь, но задам неудобные вопросы:

  1. "Это баян", подобных "учебных" статей море, в чём ценность именно этой? Для реального использования не годится из-за простоты, vuex устарел и т.д.

  2. Почему никто не пишет более интересные примеры с реальными кейсами вроде "если 10 одновременных запросов упали с 401, то не надо сразу делать 10 запросов рефреша токенов (а так и будет с кодом всех подобных статей), нужно ждать один запрос обновления, а только потом ретрай всех упавших"?

По «баяну», статей про авторизацию действительно много, но эту я написал именно потому, что не нашёл разбора, где вся цепочка показана с кодом с обеих сторон имеется ввиду - access в переменной фронта, бекенд например на Go с рефреш и логаутом, восстановление сессии после перезагрузки, и обработка протухшего токена. Про куки и локал сторадж статей много, а цельного туториала что храним access в памяти, я не встретил. Это туториал, для того чтобы понять принцип работы, какие то боевые доработки конечно же будут и часть из них вынес в статье в отдельный модуль.

По 10 запросам это справедливо параллельные запросы с протухшим токеном все падают с 401 и interceptor действительно дергает refresh на каждый запрос. Поправить можно попробовать с помощью single‑flight, один летящий refresh промис, все упавшие его ждут, затем повторяются. Про заметку спасибо большое добавлю в UPД статьи.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации