Appearance
Эксплуатация
Что делать после того, как интеграция заработала: реакция на компрометацию секрета, проверка и отзыв токенов, лимиты запросов, справочник ошибок, чек-лист перед продакшном.
Компрометация или потеря client_secret
Ротации секрета «на месте» сейчас нет — client_secret генерируется один раз при создании клиента и не может быть перевыпущен через /admin/clients/:id. Это известное ограничение архитектуры, а не недосмотр в интеграции — учитывайте его в своём плане реагирования на инциденты.
Единственный путь при компрометации или потере секрета — пересоздать клиента:
- Немедленно переведите скомпрометированный клиент в
status: suspendedна/admin/clients/:id—/authorizeи/tokenдля него сразу начнут отвечать ошибкой, это самый быстрый способ остановить злоупотребление, пока вы готовите замену. - Создайте новый клиент (
/admin/clients/new) с теми жеredirectUris,allowedScopesи брендированием — вы получите новыеclient_idиclient_secret. - Обновите конфигурацию своего приложения на новые значения и выкатите изменение.
- Удалите старый клиент (
POST /admin/clients/:id/delete) — все ранее выданные им токены и refresh token перестают быть действительными вместе с ним.
Держите этот сценарий в runbook заранее — во время реального инцидента переключение должно занимать минуты, а не требовать выяснения, как устроен процесс.
Проверка токена (/introspect)
RFC 7662. Для серверов ресурсов, которым нужно проверить активность access или refresh token, не расшифровывая JWT самостоятельно.
bash
curl -X POST http://localhost:3002/introspect \
-d "token=<access_token>" \
-d "client_id=<client_id>" \
-d "client_secret=<client_secret>"json
{
"active": true,
"sub": "user1",
"client_id": "my-app-client",
"scope": "openid profile email",
"exp": 1735000000
}Неактивный токен: { "active": false } (либо с reason, если он отозван). Клиент может интроспектировать только собственные токены — попытка проверить токен, выданный другому client_id, тоже вернёт active: false, а не данные чужого токена.
Отзыв токена (/revoke)
RFC 7009. Отзывает конкретный access или refresh token до истечения его срока — используйте при явном выходе пользователя из вашего приложения (в дополнение к RP-Initiated Logout, если он реализован) или в CLI-команде logout.
bash
curl -X POST http://localhost:3002/revoke \
-d "token=<access_token или refresh_token>" \
-d "token_type_hint=refresh_token" \
-d "client_id=<client_id>" \
-d "client_secret=<client_secret>"token_type_hint необязателен, но ускоряет обработку — сервер попробует его первым, а при несовпадении всё равно определит тип токена сам. Отозвать можно только токен, выданный вашему же client_id.
Ответ всегда 200, даже если токен не найден, уже отозван или принадлежит другому клиенту — так требует RFC 7009, чтобы по ответу нельзя было узнать, существовал ли токен вообще. Ориентируйтесь не на код ответа, а на то, что повторные запросы с этим токеном после отзыва будут отклоняться.
Лимиты запросов
POST /token — 90 запросов с одного IP-адреса за 15 минут, независимо от того, сколько разных client_id стоит за этим IP. Лимит общесистемный, а не отдельный на клиента — если ваш сервис делает много параллельных запросов client_credentials с одного адреса (например, из общего NAT-шлюза), учитывайте это при проектировании нагрузки. При превышении — 429 too_many_requests.
Справочник ошибок
| Ошибка | HTTP | Когда |
|---|---|---|
invalid_client | 401 | Неверный client_id/client_secret или клиент приостановлен |
invalid_grant | 400 | Код авторизации или refresh token недействителен, истёк или уже использован |
invalid_request | 400 | Не прошла проверка PKCE или отсутствуют обязательные параметры |
unsupported_grant_type | 400 | Неподдерживаемый grant_type |
access_denied | — | Пользователь отклонил согласие или Device Flow запрос |
authorization_pending | 400 | Device Flow: пользователь ещё не подтвердил вход |
slow_down | 400 | Device Flow: опрос /token идёт чаще interval |
expired_token | 400 | Device Flow: device_code истёк |
invalid_scope | 400 | После фильтрации по allowedScopes не остался обязательный scope |
too_many_requests | 429 | Превышен IP rate limit |
Чек-лист перед продакшном
redirectUrisклиента содержит только реальные production-адреса — без localhost и промежуточных staging-доменов, если они больше не нужны.allowedScopesограничен тем, что приложению реально нужно — не оставлен пустым «на всякий случай», если это не требуется намеренно.client_secretхранится в секрет-хранилище инфраструктуры, а не в репозитории и не в переменных окружения CI без шифрования.- Реализован обработчик
invalid_grantпри обновлении токена — истёкший/отозванныйrefresh_tokenдолжен приводить к повторному входу, а не к зависшему состоянию UI. - Если приложению важно синхронно узнавать о выходе пользователя — настроен
backchannelLogoutUriи он проверяет подписьlogout_tokenперед тем, как довериться ему. - Если клиент привязан к организации — политика входа (
loginPolicy) согласована с администратором организации и соответствует ожиданиям (MFA, домены, лимит сессий). - Runbook на компрометацию
client_secret(см. выше) существует и проверен хотя бы один раз не в боевой обстановке.