Repository navigation
Doc How Auth
Токены никогда не попадают в JavaScript. Identity выпускает JWT, Gateway прячет его в httpOnly cookie, а на каждом запросе сам достаёт из cookie и передаёт сервисам как обычный заголовок Authorization: Bearer. Сервисы ничего не знают о cookie.
- Пользователь вводит email и пароль. Фронтенд отправляет
POST /api/v1/auth/loginс телом{ email, password }. - Gateway пропускает запрос в Identity (
POST /identity/login). - Identity проверяет пароль и отвечает
{ accessToken, refreshToken, expiresAt }. - Gateway перехватывает ответ: ставит cookie
access_tokenиrefresh_token(HttpOnly,Secure,SameSite=Lax,Path=/) и вместо токенов отдаёт{ "success": true }. - Следующий запрос, например
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 минут.
- Запрос получает 401.
- Перехватчик axios вызывает
POST /api/v1/auth/refreshс пустым телом. Параллельные запросы ждут один и тот же вызовrefresh, а не запускают свои. - Gateway подставляет
refresh_tokenиз cookie в тело, Identity отзывает старый refresh-токен и выдаёт новую пару, Gateway обновляет обе cookie. - Исходный запрос повторяется. Если
refreshтоже вернул 401, фронтенд переходит на/?auth=login.
Исключение: 401 на GET /auth/me не вызывает переход на вход, это обычный способ узнать, что пользователь не вошёл.
POST /api/v1/auth/logout с пустым телом: Gateway подставляет refresh-токен из cookie, Identity отзывает его и отвечает 204, Gateway удаляет обе 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 ставятся без Expires, то есть живут до закрытия браузера; срок действия самих токенов задаёт Identity (15 минут и 7 дней). Требует проверки: задумано ли, что после перезапуска браузера нужно входить заново (задача #163).
Система
API
Сервисы
Как реализовано
Справочное
- Видение продукта
- Дорожная карта
- Этап 1: что осталось
- Этап 2: расширение
- Этап 3: масштабирование
- Концепция сайта и интерфейса
- Шаблон ТЗ