Как подключить приложение (OAuth-клиент)
This content is not available in your language yet.
Инструкция для администратора Zentro и команды приложения: зарегистрировать одно приложение, которое входит через Zentro (SSO) или ходит в API без пользователя, и дать ему токены к API.
Подключаете целый сервис (свои роли, приложения, API) — удобнее мастер: Сервисы → Подключить сервис (Подключение сервиса). Эта инструкция — для приложения вне сервиса или когда нужна ручная настройка: сторонний портал, которому нужен только вход; интеграция, которая ходит в чужой API; отдельное мобильное приложение.
Прежде чем начать
Заголовок раздела «Прежде чем начать»- Нужна роль
IDENTITY_ADMINили праваIDENTITY:OAUTH_CLIENT:*(иIDENTITY:OAUTH_RESOURCE:*, если заводите API). - Нужен второй фактор — панель попросит подтвердить себя и продолжит.
- Узнайте у команды приложения:
- что это за приложение (таблица ниже);
- адреса возврата после входа — по одному на каждую среду, точно:
https://portal.example.com/auth/callback; для мобильного — адрес его схемы (com.example.app:/oauth/callback); - куда вернуть после выхода; умеет ли приложение принимать сообщение о выходе (back-channel);
- в какие API оно будет ходить и с какими правами.
- Среды заводятся отдельно. Dev и prod — разные инсталляции Identity: в каждой свой
client_id, свой секрет.
Какое приложение
Заголовок раздела «Какое приложение»| Приложение | Что выбрать | Секрет |
|---|---|---|
| Сайт или панель со своим сервером (BFF, серверный рендеринг) | «Люди», не публичный | есть — хранится на сервере |
| Приложение целиком в браузере (SPA без сервера) или мобильное | «Люди», публичный клиент | нет — вместо него PKCE |
| Бэкенд, фоновая задача, интеграция — без пользователя | «Сервис — без пользователя» | есть |
Для SPA лучше свой небольшой сервер (BFF), который держит токены у себя: так токены не попадают в браузер. Публичный клиент — когда сервера нет совсем.
Шаг 1. Зарегистрировать приложение
Заголовок раздела «Шаг 1. Зарегистрировать приложение»OAuth-клиенты → Зарегистрировать клиента. Сначала — «Кто будет входить».
«Люди — вход в приложение через Zentro»
Заголовок раздела ««Люди — вход в приложение через Zentro»»| Поле | Что вписать |
|---|---|
| Название | Его увидят пользователи на экране согласия: Портал поставщиков |
| Redirect URI | Адреса возврата после входа, по одному в строке. Совпадение точное: схема, хост, порт, путь, слэш в конце |
| Публичный клиент | Только для SPA без сервера и мобильных. Потом не меняется — только пересозданием |
| Scopes | openid profile email: openid обязателен, profile — логин, email — почта. По умолчанию — только openid |
| Post-logout redirect URI | Куда вернуть после выхода |
| Back-channel logout URI | Адрес сервера приложения, куда Zentro сообщит о выходе пользователя. Нужен https и публичный адрес. Самый надёжный способ выхода |
| Разрешить доставку во внутреннюю сеть | Если адрес выхода внутренний (http://portal-bff:3000/…). Работает, только когда в Настройках задано oidc.backchannel_private_cidrs |
| Front-channel logout URI | Страница приложения, которую браузер откроет в скрытом окне при выходе. Браузеры часто это блокируют — лучше back-channel |
| Пространство прав | Если приложение должно знать права пользователя в каком-то сервисе — его ключ (RHM). Права придут в id_token и userinfo. Пусто — прав приложение не получит |
| Приложение организации — не спрашивать согласие | Только для своих приложений: пользователь не увидит «Разрешить». Стороннему — не ставьте |
| Тип subject | public — у человека один идентификатор во всех приложениях (если приложение сопоставляет людей с другими системами); pairwise — у каждого приложения свой псевдоним (приватнее). Потом не меняется |
| Sector identifier | Только для pairwise, если приложений с общим псевдонимом несколько; обычно пусто |
«Сервис — без пользователя»
Заголовок раздела ««Сервис — без пользователя»»Нужно только название: billing-sync. Адресов возврата, выхода и согласия у такого приложения
нет.
Что будет после «Зарегистрировать»
Заголовок раздела «Что будет после «Зарегистрировать»»Панель покажет client_id, секрет — один раз (у публичного клиента секрета нет) и сводку «Что
передать команде сервиса».
Секрет больше не покажется нигде. Скопируйте сразу и передайте команде защищённым каналом, не открытым текстом в чат или тикет. Потеряли — «Новый секрет» (ниже).
Шаг 2. Дать доступ к API
Заголовок раздела «Шаг 2. Дать доступ к API»Если приложение будет вызывать API сервиса от имени пользователя или само, API должен быть заведён как ресурс, а приложение — привязано к нему. Без привязки токен для этого API приложению не выдадут.
Если API ещё не заведён — Ресурсы OAuth → Завести ресурс:
| Поле | Что вписать |
|---|---|
| Название | Delivery API |
| Адрес (audience) | Идентификатор API в токене: https://delivery.example.com/api или rhm-delivery. API будет проверять его в каждом токене |
| Пространство прав | Ключ сервиса заглавными: DELIVERY. Права пользователя DELIVERY:… попадут в токены этого API |
Адрес и пространство прав после создания не меняются — только удалить ресурс и завести заново (привязки придётся настроить снова).
Привязать приложение — OAuth-клиенты → Ресурсы в строке приложения → Привязать ресурс, выбрать API и потолок прав — сколько из прав пользователя приложение может унести в этот API:
| Потолок | Что уйдёт в токене |
|---|---|
DELIVERY:*:* |
все права пользователя в DELIVERY |
DELIVERY:*:VIEW |
только чтение, даже если у человека есть запись |
| пусто | прав нет, только доступ — так настраивают сервисные приложения |
В токене — права пользователя ∩ потолок. Панель подсказывает права из ролей этого пространства. Потолок можно поменять в любой момент — действует со следующего токена.
Кто ходит в API и с каким потолком — Ресурсы OAuth → Клиенты в строке API.
Шаг 3. Передать команде приложения
Заголовок раздела «Шаг 3. Передать команде приложения»Сводка «Что передать команде сервиса» — с кнопкой копирования. Для приложения для людей:
Приложение: Портал поставщиковIssuer: https://id.example.com ← адрес Identity этой средыDiscovery: https://id.example.com/.well-known/openid-configurationClient ID: cid_…Client secret: передаётся отдельно (у публичного: «нет (публичный клиент, PKCE)»)Redirect URI: https://portal.example.com/auth/callbackПространство прав: RHMДля сервисного — вместо адресов возврата Получение токена: client_credentials и Token endpoint.
Секрета в сводке нет намеренно — сводку можно переслать, секрет передайте отдельно. Допишите адрес (audience) каждого API, к которому привязали приложение.
Что делает команда приложения
Заголовок раздела «Что делает команда приложения»Всё, что нужно, приложение берёт из Discovery — адреса не зашиваются.
Вход пользователя — Authorization Code + PKCE (S256, обязателен всем, и с секретом тоже):
- Браузер →
authorizeсclient_id,redirect_uri,response_type=code,scope,code_challenge,code_challenge_method=S256,state,nonce. Пользователь входит на экране Zentro, при необходимости — «Разрешить». - Возврат на
redirect_uriсcode→ сервер приложения меняет его наtokenсcode_verifier(и секретом —client_secret_basicилиclient_secret_post). Код живёт 60 секунд. - Ответ:
id_token(кто вошёл;permissions— права в пространстве приложения),access_token,refresh_token.
Полезное: prompt=login — всегда спросить пароль заново, max_age=N — если вход был дольше N
секунд назад, prompt=none — тихая проверка входа без экрана.
Вызов API: access_token без resource= годен только для userinfo. Для API — токен
resource=<адрес API> (при обмене кода, на каждом refresh заново — он не запоминается).
Сервисное приложение:
curl -u "$CLIENT_ID:$CLIENT_SECRET" \ -d grant_type=client_credentials \ -d resource=https://delivery.example.com/api \ https://id.example.com/oidc/token# → {"access_token":"…","expires_in":900,"token_type":"Bearer"}Без resource= токен ни в какой API не годится. Токен живёт 15 минут, refresh нет — за новым
приходят так же. В токене sub = azp = client_id, прав нет: API пускает сервис по client_id.
Проверка токена в API — локально по ключам из jwks_uri: подпись, exp, iss = issuer из
Discovery, aud = свой адрес (чужой — отклонять), дальше permissions (пользователь) или
azp (сервис).
Ключ берите по kid из заголовка токена и принимайте RS256, ES256 и EdDSA: по умолчанию
Zentro подписывает RS256, но администратор может сменить алгоритм или ключ. Ключи кэшируйте (час —
нормально), а на незнакомый kid перечитывайте jwks_uri — иначе после смены ключа API начнёт
отклонять новые токены. Zentro публикует новый ключ за сутки до того, как начнёт им подписывать.
Выход: end_session_endpoint из Discovery с id_token_hint и post_logout_redirect_uri.
Сервер приложения при выходе ещё и отзывает свой refresh-токен — revocation_endpoint (RFC 7009) с
секретом клиента: гаснет сессия этого приложения, вход в Zentro и другие приложения остаются.
Сервисное приложение так же отзывает свой токен, когда задача закончена.
Проверка «токен ещё жив» — introspection_endpoint (RFC 7662), только с секретом клиента:
видны свои токены и токены, выданные для API своего сервиса; остальное — {"active": false}.
Шаг 4. Проверить
Заголовок раздела «Шаг 4. Проверить»- «Проверить» в строке приложения (Приложения) — панель сверит настройки (секрет, PKCE, адреса по
http) и попробует открыть адреса возврата и выхода с сервера. Ошибки — первыми. «Пропущено» — не
ошибка: внутренний адрес или схема приложения (
myapp://) открывается у пользователя, сервер их не видит. «С сервера недоступен» — тоже не обязательно беда: браузер пользователя может видеть адрес, который не видит сервер. - Откройте приложение и нажмите «Войти» — откроется экран входа Zentro.
- Войдите. Если приложение не «приложение организации» — экран согласия с его названием.
- Вы вернулись в приложение, оно знает, кто вы (и ваши права, если задано пространство).
- Вызов API из приложения проходит; без привязки к API —
invalid_target. - Сервисное: запрос токена из примера выше отдаёт
access_token.
Управлять приложением
Заголовок раздела «Управлять приложением»OAuth-клиенты → строка приложения:
-
«Изменить» — адреса, scopes, выход, пространство прав, согласие, статус. Секрет правкой не меняется. Тип subject и «публичный клиент» не меняются — только пересозданием (новый
client_id, интеграцию придётся перенастроить). У сервисного меняются только название и статус. -
Статус «Отключён» — временно остановить: вход, обмен кода, refresh и
client_credentialsпрекращаются сразу. Включили — работает как было. -
«Новый секрет» — выпустить новый секрет;
client_id, привязки и согласия сохранятся:- «Действует ещё сутки» — плановая смена: старый секрет работает ещё 24 часа, команда успеет переключиться;
- «Перестаёт работать сразу» — если секрет утёк.
Новый секрет показывается один раз. У публичного клиента секрета нет.
-
«Ресурсы» — привязки к API и потолки прав (шаг 2).
-
«Отозвать токены» — экстренно, если приложение скомпрометировано или ведёт себя странно, а удалять его нельзя: все пользователи выходят из него (приложению уходит уведомление о выходе), всё выданное ему до этого момента перестаёт действовать, включая сервисные токены. Клиент, привязки и согласия остаются — дальше приложение получает токены как обычно. Утёк секрет — ещё и «Новый секрет» → «Перестаёт работать сразу». Нужен второй фактор.
-
«Удалить» — необратимо: вход и refresh прекращаются сразу, согласия пользователей и привязки к API снимаются, выданные токены отзываются. Вернуть нельзя — только регистрировать заново, с новым
client_idи секретом.
Про отозванные токены: Zentro (userinfo, интроспекция) перестаёт их принимать сразу. API, которые
проверяют токен у себя по ключам, пускают по уже выданному до его срока — до 15 минут; кому
нужно сразу — пусть спрашивают Zentro (introspection_endpoint из Discovery).
Пользователь сам видит приложения, которым дал доступ, и может отозвать согласие — в кабинете, Приложения с доступом.
Частые ошибки
Заголовок раздела «Частые ошибки»| Что видно | Причина | Что сделать |
|---|---|---|
Ошибка про redirect_uri при входе |
Адрес не совпал с зарегистрированным | Сверить посимвольно: http/https, порт, слэш в конце; добавить адрес в «Изменить» |
invalid_client |
Неверный client_id/секрет, клиент отключён или удалён; или прошли сутки после «Нового секрета» |
Проверить статус; выпустить новый секрет |
invalid_target |
Приложение не привязано к API, ошибка в адресе API или API выключен | Ресурсы в строке приложения; Ресурсы OAuth — адрес и статус |
invalid_scope при входе |
Приложение просит scope, которого нет в его списке (или забыло openid) |
Добавить scope в «Изменить» или убрать из запроса |
invalid_grant при обмене кода |
Код просрочен (60 с), уже использован или code_verifier не тот |
Повторить вход; проверить PKCE |
| API отвечает 401 на токен | Токен без resource= или для другого API (aud не тот) |
Запрашивать токен с resource=<адрес этого API> |
| В токене нет прав | Пустой потолок, нет пространства прав или у человека нет роли | Потолок в Ресурсах; пространство — «Изменить»; роль — Пользователи |
| Пользователь каждый раз видит «Разрешить» | Приложение стороннее — так и должно быть; своё — не помечено | Для своего: «Приложение организации» |
| «Доставка во внутреннюю сеть не настроена…» | Галка внутренней сети без oidc.backchannel_private_cidrs |
Задать сети в Настройках — ссылка в ошибке |
| Вход обрывается на пустой странице | У Identity не настроен адрес экрана входа | Вопрос к тем, кто разворачивал Identity |
| Секрет потерян | Показывается один раз | «Новый секрет» |
| Все пользователи разом вышли из приложения | Кто-то нажал «Отозвать токены» или удалил клиента | Проверить аудит; приложение просто запрашивает токены заново |
| API пускает по отозванному токену | API проверяет токен у себя по ключам — отзыв увидит не позже чем через 15 минут | Если нужно сразу — проверять через introspection_endpoint |