# authn-authz Specification ## Purpose Вход в ядро по JWT внешнего SSO (РАИСА): пользователь находится по email в `app_user`, его эффективные права — объединение прав его ролей из БД; любой защищённый маршрут объявляет требуемое право одной зависимостью. Для разработки — эмитент токенов за флагом. ## Requirements ### Requirement: Личность из JWT, пользователь из БД Защищённый маршрут SHALL требовать заголовок `Authorization: Bearer `. Ядро SHALL проверить подпись и срок токена настроенным проверяющим (dev HS256 при `AUTH_DEV_ISSUER=true`, иначе JWKS/публичный ключ по `AUTH_*`), извлечь email из claim `AUTH_EMAIL_CLAIM` (по умолчанию `email`) и найти `app_user` с этим `email` и `is_active = true`. Нет или невалидный токен → 401; пользователь не найден или неактивен → 403. Тело ошибки — `{"detail": "<причина по-русски>"}`. #### Scenario: Валидный токен активного пользователя - **WHEN** запрос несёт корректный токен с `email = ka_rf@armka.local`, и такой активный пользователь есть - **THEN** маршрут выполняется от имени этого `app_user` #### Scenario: Пользователя нет в системе - **WHEN** токен валиден, но `app_user` с таким email отсутствует - **THEN** ответ 403, `detail` сообщает, что пользователь не зарегистрирован в АРМ #### Scenario: Истёкший или подделанный токен - **WHEN** срок токена истёк или подпись не проходит - **THEN** ответ 401, тело `{"detail": …}` ### Requirement: Эффективные права и зависимость `require` `effective_permissions(user)` SHALL быть объединением `permission.code` по всем ролям пользователя (`user_role → role_permission → permission`); код роли в проверках MUST NOT использоваться. Зависимость `require("")` SHALL возвращать 403, если кода нет в эффективных правах, и MUST NOT обращаться к БД повторно в рамках одного запроса. #### Scenario: Право есть - **WHEN** пользователь с ролью `KA_GO` вызывает маршрут с `require("KFO_VERIFY")` - **THEN** маршрут выполняется #### Scenario: Права нет - **WHEN** пользователь с ролью `EXPERT` вызывает маршрут с `require("DOCUMENT_EDIT")` - **THEN** ответ 403, `detail` называет недостающее право #### Scenario: Две роли - **WHEN** пользователю назначены роли `KA_RF` и `CURATOR_GO` - **THEN** его эффективные права — объединение прав обеих ролей без дубликатов ### Requirement: `GET /api/v1/me` Маршрут SHALL возвращать текущего пользователя: `id`, `email`, `full_name`, `regional_office {id, name, is_head_office}`, `business_segment`, `roles` (список `code`), `permissions` (отсортированный список `code`). Это единственный маршрут Среза 0, доступный любому аутентифицированному пользователю без `require`. #### Scenario: Ответ для dev-пользователя - **WHEN** `ka_rf@armka.local` (роль `KA_RF`) запрашивает `/api/v1/me` - **THEN** ответ 200 содержит `roles = ["KA_RF"]` и `permissions`, равные правам `KA_RF` из матрицы §10 ### Requirement: Dev-эмитент токенов только в режиме разработки При `AUTH_DEV_ISSUER=true` **и** `DEBUG=true` ядро SHALL предоставлять `POST /api/v1/dev/token` с телом `{"email"}`, возвращающий HS256 JWT (срок 8 часов) для существующего активного пользователя. При любом другом сочетании флагов маршрут MUST NOT существовать (404), а dev-проверяющий MUST NOT принимать токены. #### Scenario: Получение dev-токена - **WHEN** `AUTH_DEV_ISSUER=true`, `DEBUG=true` и запрошен токен для `admin@armka.local` - **THEN** ответ 200 `{access_token, token_type: "bearer"}`, токен принимается `/api/v1/me` #### Scenario: Прод-конфигурация - **WHEN** `DEBUG=false` - **THEN** `POST /api/v1/dev/token` возвращает 404, токен, подписанный dev-секретом, отвергается с 401