Skip to content

Doc How Auth

PlutoGr edited this page Oct 17, 2026 · 2 revisions

Как работает вход и сессия

Токены никогда не попадают в JavaScript. Identity выпускает JWT, Gateway прячет его в httpOnly cookie, а на каждом запросе сам достаёт из cookie и передаёт сервисам как обычный заголовок Authorization: Bearer. Сервисы ничего не знают о cookie.

Простой пример

  1. Пользователь вводит email и пароль. Фронтенд отправляет POST /api/v1/auth/login с телом { email, password }.
  2. Gateway пропускает запрос в Identity (POST /identity/login).
  3. Identity проверяет пароль и отвечает { accessToken, refreshToken, expiresAt }.
  4. Gateway перехватывает ответ: ставит cookie access_token и refresh_token (HttpOnly, Secure, SameSite=Lax, Path=/) и вместо токенов отдаёт { "success": true }.
  5. Следующий запрос, например GET /api/v1/bookings/my, браузер отправляет с cookie сам. Gateway видит cookie, добавляет Authorization: Bearer <access_token>, проверяет JWT и роль, проксирует в Booking.

Участники

Где Класс Роль
Identity AuthController, LoginCommandHandler, JwtTokenService проверка пароля, выпуск и ротация токенов
Gateway AuthResponseTransformProvider токены из ответа Identity → cookie; при logout cookie удаляются (Max-Age=0)
Gateway CookieToAuthHeaderMiddleware cookie access_token → Authorization: Bearer, если заголовка ещё нет
Gateway AuthRequestMiddleware пустой POST /auth/refresh или /auth/logout → тело { refreshToken } из cookie
Shared JwtAuthenticationExtensions одинаковая проверка JWT в Gateway и сервисах
Фронтенд src/api/client.ts axios с withCredentials: true; на 401 один раз вызывает refresh и повторяет запрос
Фронтенд src/store/authStore.ts состояние входа; проверка через GET /auth/me

Обновление токена

Access-токен живёт 15 минут.

  1. Запрос получает 401.
  2. Перехватчик axios вызывает POST /api/v1/auth/refresh с пустым телом. Параллельные запросы ждут один и тот же вызов refresh, а не запускают свои.
  3. Gateway подставляет refresh_token из cookie в тело, Identity отзывает старый refresh-токен и выдаёт новую пару, Gateway обновляет обе cookie.
  4. Исходный запрос повторяется. Если refresh тоже вернул 401, фронтенд переходит на /?auth=login.

Исключение: 401 на GET /auth/me не вызывает переход на вход, это обычный способ узнать, что пользователь не вошёл.

Выход

POST /api/v1/auth/logout с пустым телом: Gateway подставляет refresh-токен из cookie, Identity отзывает его и отвечает 204, Gateway удаляет обе cookie.

Чат и cookie

SignalR открывает WebSocket к /api/v1/chat/hubs/chat с withCredentials: true, cookie уходит вместе с рукопожатием, и CookieToAuthHeaderMiddleware делает из неё заголовок. Для пути хаба middleware также принимает токен в параметре access_token строки запроса (так SignalR передаёт токен, когда cookie недоступна).

Почему так

  • httpOnly cookie недоступна JavaScript, поэтому XSS-скрипт не может украсть токен.
  • SameSite=Lax не отправляет cookie в фоновых запросах с чужих сайтов; CORS разрешает только origin сайта.
  • Ротация refresh-токена: украденный и уже использованный токен не сработает второй раз.
  • Сервисы проверяют JWT сами, даже если Gateway уже проверил: запрос в обход Gateway внутри сети без токена не пройдёт.

Сроки жизни cookie

Cookie ставятся без Expires, то есть живут до закрытия браузера; срок действия самих токенов задаёт Identity (15 минут и 7 дней). Требует проверки: задумано ли, что после перезапуска браузера нужно входить заново (задача #163).

См. также: Identity · Gateway

Clone this wiki locally