Интеграция с identity
Зачем нужно
Документ описывает, как 6 не-identity доменов потребляют аутентификацию и авторизацию из identity, как распространяется токен пользователя и как передаётся контекст действия (ребёнок, организация).
Главная схема
- identity — единственный authorization server экосистемы.
- Все frontend-приложения логинят пользователя через identity (OIDC).
- Все backend-сервисы валидируют access tokens через JWKS identity (offline) и опционально через introspection.
- Service-to-service вызовы используют OAuth client_credentials grant с scoped permissions.
- Действие в контексте ребёнка/организации передаётся отдельным заголовком
X-Actor-Context, не подменяяsub.
Поток входа пользователя в frontend
lms-webредиректит неаутентифицированный запрос наhttps://id.systematika.tld/authorize?...(OIDC + PKCE).- identity показывает экран входа.
- После успешного входа возвращается authorization code.
- Code exchange выполняет доверенный backend-компонент: BFF/Next server route приложения или identity callback flow. Browser JS не получает refresh token.
- Refresh token хранится только в HttpOnly Secure SameSite=Strict cookie на домене identity или в защищённом storage backend-приложения. Access token хранится в memory и обновляется через backend-controlled refresh endpoint.
- Refresh endpoint защищён CSRF-механизмом, rotation и device binding; cross-subdomain refresh требует отдельного ADR с точной cookie/session моделью.
Access token
- Формат: JWT, RS256.
- Контракт access token закреплён в ADR-033.
- Время жизни: 15 минут.
iss = https://id.systematika.tld.aud— список audience (домены, для которых токен валиден).sub—user_id.scope— пространство-разделённые scopes.- Дополнительные claims:
auth_method,permission_versionили bounded permissions summary.family_ids/organization_idsдопускаются только как bounded context summary для first-party apps. PII such as email belongs to ID token/userinfo and must not be required in API access token.
Refresh token
- Хранится только в HttpOnly cookie или в защищённом storage backend-приложения.
- Ротируется при каждом обновлении.
- Хранится с device binding и метаданными (см. identity/security.md).
Actor context
Контекст действия (actor_context) — отдельный заголовок:
X-Actor-Context: {"kind":"child_delegated","studentProfileId":"...","familyGroupId":"..."}
Возможные значения kind:
personal— пользователь действует от себя (по умолч анию, заголовок можно опускать);child_delegated— взрослый действует от имениstudent_profileребёнка;family_adult— взрослый смотрит или управляет даннымиstudent_profileребёнка без подмены;organization_member— пользователь действует от организации;team_member— пользователь действует от команды;admin— администратор;oauth_client— внешний сервис;plugin— плагин.
Сервер обязан проверить, что пользователь имеет право на этот контекст (через identity API или claims в токене), прежде чем выполнять действие.
X-Actor-Context является заявленным намерением клиента, а не доверенным фактом. Backend вычисляет effective actor context из JWT sub, permission checks identity и ownership целевого объекта. Поле initiatedBy не принимается от клиента: оно всегда выводится из JWT sub. При конфликте JWT, actor context и ownership целевого объекта запрос отклоняется 403.
Для family contexts главным subject является studentProfileId. linkedUserId/subjectUserId может использоваться только как optional linked user reference, если у student_profile есть linked_user_id. Авторизация ребёнк а на другом устройстве через child_device_authorization не передаётся через X-Actor-Context: она завершает pre-auth flow и создаёт обычную user_session ребёнка.
Service-to-service
- Каждый backend-сервис регистрируется как
oauth_clientсclient_credentialsgrant. client_idиclient_secretхранятся в секретах окружения сервиса.- Получает короткоживущий access token со своими scopes.
- Использует токен в заголовке
Authorization: Bearer ....
Пример scopes для service tokens:
service:crm.entitlements.readservice:crm.entitlements.consumeservice:competitions.results.read
Формат service token:
- JWT RS256,
sub = oauth_client.client_id; actor.serviceClient = client_id;audсодержит только целевой backend-сервис;- TTL 5 минут;
- scopes только в формате
service:<permission>изpermissions-model.md; - генерация только через OAuth
client_credentials; ручные long-lived bearer tokens запрещены.
Проверка токена в backend-сервисе
Backend-сервис не доменa identity:
- Получает JWKS с identity по
https://id.systematika.tld/.well-known/jwks.json, кеширует. - Валидирует подпись,
iss,aud,exp,nbf. - Проверяет наличие нужного scope.
- Извлекает
sub(user_id) и claims. - Проверяет
X-Actor-Contextчерез permissions check. - Прокидывает correlation:
X-Request-Id,traceparent.
Реализация — общий пакет packages/auth-client.
Получение профиля и ролей
Backend-сервис не дублирует пользовательские данные. Если нужны атрибуты, не входящие в access token:
GET https://id.systematika.tld/userinfo— стандартный OIDC userinfo;GET https://id.systematika.tld/api/v2/identity/admin/users/{id}— расширенный профиль (требует scope);- кеш ответов: до 60 секунд по user_id.
Пользовательские роли в чужом домене
Роли пользователя глобальные, но пермишны конкретного домена интерпретируются доменом. Подробности — в permissions-model.md.
Logout
- Frontend вызывает identity end_session.
- Identity отзывает refresh tokens сессии.
- Backend-сервисы реагируют на событие
identity.session.revoked(см.events-bus.md) и инвалидируют локальный кеш user_id.
Запрещено
- Реализовывать собственный логин в любом домене кроме identity.
- Хранить копию пароля.
- Использовать
subчужого пользователя для подмены. - Выдавать access tokens вне identity.
- Игнорировать
X-Actor-Contextдля действий, требующих контекста. - Передавать токены через query string.