Skip to content

Эксплуатация

Что делать после того, как интеграция заработала: реакция на компрометацию секрета, проверка и отзыв токенов, лимиты запросов, справочник ошибок, чек-лист перед продакшном.


Компрометация или потеря client_secret

Ротации секрета «на месте» сейчас нет — client_secret генерируется один раз при создании клиента и не может быть перевыпущен через /admin/clients/:id. Это известное ограничение архитектуры, а не недосмотр в интеграции — учитывайте его в своём плане реагирования на инциденты.

Единственный путь при компрометации или потере секрета — пересоздать клиента:

  1. Немедленно переведите скомпрометированный клиент в status: suspended на /admin/clients/:id/authorize и /token для него сразу начнут отвечать ошибкой, это самый быстрый способ остановить злоупотребление, пока вы готовите замену.
  2. Создайте новый клиент (/admin/clients/new) с теми же redirectUris, allowedScopes и брендированием — вы получите новые client_id и client_secret.
  3. Обновите конфигурацию своего приложения на новые значения и выкатите изменение.
  4. Удалите старый клиент (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_client401Неверный client_id/client_secret или клиент приостановлен
invalid_grant400Код авторизации или refresh token недействителен, истёк или уже использован
invalid_request400Не прошла проверка PKCE или отсутствуют обязательные параметры
unsupported_grant_type400Неподдерживаемый grant_type
access_deniedПользователь отклонил согласие или Device Flow запрос
authorization_pending400Device Flow: пользователь ещё не подтвердил вход
slow_down400Device Flow: опрос /token идёт чаще interval
expired_token400Device Flow: device_code истёк
invalid_scope400После фильтрации по allowedScopes не остался обязательный scope
too_many_requests429Превышен IP rate limit

Чек-лист перед продакшном

  • redirectUris клиента содержит только реальные production-адреса — без localhost и промежуточных staging-доменов, если они больше не нужны.
  • allowedScopes ограничен тем, что приложению реально нужно — не оставлен пустым «на всякий случай», если это не требуется намеренно.
  • client_secret хранится в секрет-хранилище инфраструктуры, а не в репозитории и не в переменных окружения CI без шифрования.
  • Реализован обработчик invalid_grant при обновлении токена — истёкший/отозванный refresh_token должен приводить к повторному входу, а не к зависшему состоянию UI.
  • Если приложению важно синхронно узнавать о выходе пользователя — настроен backchannelLogoutUri и он проверяет подпись logout_token перед тем, как довериться ему.
  • Если клиент привязан к организации — политика входа (loginPolicy) согласована с администратором организации и соответствует ожиданиям (MFA, домены, лимит сессий).
  • Runbook на компрометацию client_secret (см. выше) существует и проверен хотя бы один раз не в боевой обстановке.