Архитектура: модули и контракты
┌──────────────────────────┐
│ core │
│ OAuth2 · OIDC · GNAP │
│ сессии · токены · ключи │
└─────────────┬─────────────┘
│ Admin API (контракт)
┌───────────────┴───────────────┐
│ │
┌───────┴────────┐ ┌───────┴────────┐
│ consent │ │ rbac │
│ engine + │ │ роли / политики │
│ plugins: │ │ (опционально) │
│ пароль, SMS, │ └────────────────┘
│ Google/FB/YA… │
└────────────────┘Каждая стрелка на диаграмме — явный контракт (API), не общий internal-код. Замените consent на свою реализацию, соблюдая контракт — core не заметит разницы.
Почему так, а не монолит
coreотвечает только за протокол: сессии, OAuth 2.0, OIDC, GNAP. Он ничего не знает о том, как вы аутентифицируете пользователей — паролем, SMS-кодом или через внешний IdP.consent— отдельный сервис: engine (оркестрация login/consent, вызовы Admin APIcore) + plugins (конкретные способы входа). Плагин — это свой способ входа без форка ядра AS.rbac— авторизация поверх токенов, тоже опциональна.
Что это даёт на практике
- Login/UI/SMS/соцпровайдеров можно вынести в свой контур, оставив протокол токенов в
core. - Не нужно тащить user-store и админку IdP, если она у вас уже есть.
- В compliance-периметр можно пустить только
core, а login оставить в другом сегменте сети. - Собрать «тонкий» AS для B2B API и «толстый» стек с consent+rbac для продуктов с людьми — из одной линейки модулей.
Поставка
Разработка идёт в одном монорепозитории, но поставка — отдельные артефакты на модуль (бинарник / образ / пакет). Полирепо — опционально, после стабилизации контрактов между модулями.
Управляемый logout
Один AS часто обслуживает линейку продуктов. Конфиг session.logout_scope решает, что значит кнопка «выйти»:
| Значение | Поведение /oauth2/logout |
|---|---|
session (default) | Завершить только текущую SSO-сессию |
device | Все сессии этого пользователя на этом браузерном устройстве |
subject | Все сессии пользователя на всех устройствах |
Без переписывания relying party и без надежды, что каждое приложение само отзовёт свои токены.