Files
docs/domains/authentication/overview.md
T
ksv741 97069d6f6d
Docs security / security (pull_request) Successful in 6s
Docs verify / verify (pull_request) Successful in 11s
Conventional commits / commits (pull_request) Successful in 16s
Docs security / security (push) Successful in 9s
Docs verify / verify (push) Successful in 10s
docs: make documentation checks self-contained
2026-09-15 20:45:40 +03:00

123 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Аутентификация и сессии
Аутентификация связывает локального [пользователя](../../glossary.md#user)
с его сессией WealthLedger. Она открывает доступ к приложению; доступ
к брокерским данным определяется отдельным
[подключением T-Bank](../../integrations/tbank.md). Backend проверяет
учётные данные и управляет сессиями, frontend восстанавливает состояние
входа и выбирает доступные маршруты.
## Регистрация и вход
Пользователь регистрируется или входит по email и паролю. Регистрация сразу
создаёт первую сессию. Внешние пробелы email удаляются, буквы приводятся
к нижнему регистру. Backend требует пароль не короче 12 символов и не длиннее
72 UTF-8 байтов.
**Известное расхождение:** сохранённое требование регистрации и проверка
в форме frontend считают нижнюю границу в UTF-8 байтах, а backend — в символах.
Не-ASCII пароль может пройти форму и получить отказ API. Это не принятое
изменение password policy; требуется отдельное согласованное решение
о проверке пароля и подтверждение полного HTTP-потока.
Access token действует 15 минут и хранится только в памяти браузера.
Refresh token имеет серверный срок 7 дней, заменяется при восстановлении
сессии и передаётся в cookie `refresh_token` с `httpOnly` и `SameSite=Lax`.
Сроки определены в [спецификации сессий](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/user-authentication/spec.md#requirement-access-и-refresh-сессии)
и [ADR 006](../../adr/006-auth-session-policy.md).
После перезагрузки SPA получает новый access token через refresh-cookie.
Пока результат неизвестен, пользователь видит нейтральный skeleton каркаса
без преждевременного показа public или protected содержимого. После
завершения восстановления приложение выбирает доступный маршрут.
Все маршруты, кроме `/login` и `/register`, требуют сессию. После входа
пользователь возвращается на исходный внутренний маршрут, если он был.
Logout доступен в настройках: frontend очищает локальную сессию независимо
от состояния сети, а backend отзывает серверную сессию при предъявлении
её действительного refresh-cookie.
## Восстановление сессии
Динамическая схема показывает восстановление после reload между SPA, auth API
и локальным хранилищем сессий. SQLite здесь — файл базы backend.
```mermaid
sequenceDiagram
participant F as React SPA
participant B as Backend API
participant D as Локальная SQLite
Note over F: Reload: access token в памяти отсутствует
F->>B: Refresh с httpOnly cookie
B->>D: Проверить Session и текущий hash token
alt Действительная сессия, ротация выиграна
B->>D: Атомарно заменить hash и срок
B-->>F: Access token, профиль, новая refresh-cookie
F->>B: Protected request с Bearer
else Cookie нет или refresh отклонён
B-->>F: 401 и очистка cookie
Note over F: Готовое неавторизованное состояние
end
```
В одном экземпляре frontend одновременные refresh используют один
незавершённый запрос. Между вкладками используется Web Locks, если браузер
его поддерживает. Backend всё равно защищает ротацию атомарно: координация
браузеров не заменяет серверную проверку.
Обычный защищённый запрос с `401 UNAUTHORIZED` проходит refresh и один повтор
через общий транспорт; auth endpoints из этого цикла исключены. Само
истечение access token не запускает фоновый таймер refresh.
## HTTP-граница
Endpoints, статусы и формы публичных ответов определяет backend OpenAPI;
граница производного клиента описана в
[HTTP API](../../architecture/http-api.md#источник-контракта).
Refresh-cookie ограничена auth API. Признак Secure зависит от режима
окружения: в development допускается локальный HTTP, в остальных режимах
Secure-cookie требует защищённого соединения.
HTTP-ошибка и транспортная ошибка refresh одинаково завершают начальное
восстановление готовым неавторизованным состоянием. При refresh после
защищённого `401` frontend очищает сессию в памяти и query cache, сохраняя
исходный `401` для перехода ко входу. Общая форма ошибок и известное
расхождение деталей валидации находятся в
[HTTP API](../../architecture/http-api.md#error-contract).
## Ограничения
Описанный auth flow ограничен регистрацией, входом, восстановлением сессии
и logout. Подтверждение email, восстановление или смена пароля, смена email,
удаление аккаунта, список устройств, logout всех устройств и rate limit
попыток входа не входят в эту реализованную возможность. Access token
может оставаться действительным до 15 минут после logout.
Если несколько клиентов одновременно предъявляют один действительный
refresh token, сервер завершает одну ротацию успешно, остальные запросы
получают `401`. Сессия победившего запроса остаётся действительной. Уже
заменённый refresh token также даёт `401`, но сам по себе не отзывает сессию:
механизм не хранит историю token или grace-window, чтобы отличить
конкурентный запрос от replay. Это ограничение и его причины сохранены
в [ADR 009](../../adr/009-concurrent-refresh-rotation-policy.md).
Refresh-cookie не задаёт собственные `maxAge` или `expires`.
Семидневный серверный срок refresh token не является обещанием сохранения
входа после закрытия браузера.
## Ответственность и проверка
Backend проверяет учётные данные и tokens, хранит состояние Session и
атомарно выполняет ротацию. Frontend управляет состоянием входа,
восстановлением после reload и доступностью экранов; общий HTTP-транспорт
передаёт Bearer token и выполняет описанный refresh/retry.
Проверки конкурентной ротации, браузерного состояния и транспорта охватывают
разные границы. Их изолированная проверка не заменяет полный HTTP-поток
и проверку атомарности с реальной изолированной базой.
Согласованное поведение находится в workspace-спецификации
[User authentication](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/user-authentication/spec.md).
Правила начального ожидания — в
[состояниях интерфейса](../../architecture/cross-cutting/ui-resilience.md).