22 lines
3.4 KiB
Markdown
22 lines
3.4 KiB
Markdown
# Authentication
|
||
|
||
## User flow
|
||
|
||
Пользователь регистрируется или входит по email и паролю. Регистрация сразу создаёт первую сессию. Email сохраняется в нормализованном виде; пароль должен содержать от 12 до 72 UTF-8 байтов.
|
||
|
||
Access token живёт 15 минут только в памяти браузера. Refresh token живёт 7 дней в cookie `refresh_token` с `httpOnly` и `SameSite=Lax`; при восстановлении сессии он заменяется. После перезагрузки приложение восстанавливает access token через refresh-cookie до показа защищённых маршрутов. Пока результат восстановления неизвестен, frontend показывает нейтральный structural skeleton каркаса без public или protected route content; после завершения bootstrap сохраняются прежние decisions и redirects.
|
||
|
||
Все маршруты, кроме `/login` и `/register`, требуют сессию. После входа пользователь возвращается на исходный внутренний маршрут, если он был. Logout доступен в настройках, очищает локальную сессию независимо от состояния сети и отзывает серверную сессию при доступном refresh-cookie.
|
||
|
||
## API
|
||
|
||
`POST /api/v1/auth/register`, `POST /api/v1/auth/login` и `POST /api/v1/auth/refresh` возвращают профиль и access token с HTTP `200`. `POST /api/v1/auth/logout` отвечает `204`. `GET /api/v1/auth/me` требует Bearer access token.
|
||
|
||
Ошибки API имеют `application/problem+json` с полями `status` и `code`. Ошибки валидации содержат `errors` с JSON Pointer полей. HTTP- и транспортная ошибка refresh одинаково завершают cold start готовым неавторизованным состоянием; при refresh после protected `401` frontend очищает in-memory session и React Query cache, сохраняя исходный `401` для существующего login flow.
|
||
|
||
## Limitations
|
||
|
||
MVP не включает подтверждение email, восстановление или смену пароля, смену email, удаление аккаунта, список устройств, logout всех устройств или rate limit попыток входа. Access token может оставаться действительным до 15 минут после logout.
|
||
|
||
Если несколько клиентов одновременно предъявляют один действительный refresh token, сервер завершает одну ротацию успешно, а остальные запросы получают `401`; сессия победившего запроса остаётся действительной. Уже заменённый refresh token также даёт `401`, но сам по себе не отзывает сессию: MVP не хранит историю token или grace-window, чтобы отличить конкурентный запрос от replay.
|