Аутентификация и гранты
У платформы три тира доступа: полный (владелец/админ), read-only scoped-токены и агент-токены — про них эта страница. Агент-токен — это JWT с широким чтением (секреты всегда вымараны) и записью только в явно выданный пул контрактов.
Как выпускается агент-токен
Заголовок раздела «Как выпускается агент-токен»Токены агентов минтит только суперпользователь (владелец) — POST /api/v1/auth/agent-token отвечает всем остальным 403. Агент не может
выпустить или продлить свой токен сам. Запрос владельца выглядит так:
{ "email": "my-agent@example.dev", "expires_days": 90, "revoke_prior": true, "grants": [ { "salescontract": 12345, "capabilities": ["submit", "launch", "cancel", "edit_config"] } ]}grantsобязателен и непуст — токен без пула отклоняется (400).expires_days(1–365, по умолчанию 90) задаёт срок жизни JWT.revoke_prior: true(по умолчанию) немедленно гасит все ранее выпущенные токены этой агент-личности.
Ответ содержит access_token (отправляй как
Authorization: Bearer <token>), срок в секундах и id агента.
Грант-пул
Заголовок раздела «Грант-пул»Права записи живут в одной таблице: строка на пару (агент, контракт) со
списком capabilities — подмножество submit, launch, cancel,
edit_config, publish. Default deny: нет строки — нет доступа, а
publish на прод-контрактах не выдаётся по умолчанию — его нужно
запрашивать явно. Управление задачами/дефектами — отдельная глобальная
capability (manage_task), не привязанная к контрактам.
⚠️ Ловушка «токен заменяет пул»
Заголовок раздела «⚠️ Ловушка «токен заменяет пул»»Минт токена удаляет весь грант-пул агента и вставляет ровно то, что перечислено в запросе. Перевыпуск токена «чтобы добавить один контракт» со списком из одного контракта молча срежет все остальные гранты. Два безопасных способа расширить пул:
- Перечислить весь пул в запросе: сначала получить текущие гранты, затем передать старые + новый вместе.
- Аддитивный грант без перевыпуска: санкционированный путь — вставка одной новой грант-строки напрямую (операция владельца) — действующий токен подхватывает её сразу, всё остальное не меняется.
После любого перевыпуска агенту стоит перепроверить my_capabilities
до действий.
Если не работает
Заголовок раздела «Если не работает»| Ответ | Причина | Действие |
|---|---|---|
401 с деталью о токене | Подпись невалидна, токен истёк или не тот тип | Запросить свежий токен у владельца |
401 token revoked | Для твоей личности выпущен более новый токен с revoke_prior: true — твой мёртв, даже если срок не вышел | Используй новейший токен; он всегда один |
401 user not found or inactive | Агент-личность деактивирована | Эскалируй владельцу |
403 superuser required | Ты позвал owner-only роут (например, минт токена) | Не надо — попроси владельца |
403 с именем контракта/capability | Токен валиден, но запись целится в контракт вне пула или требует невыданной capability | Проверь my_capabilities; запроси конкретный грант |
403 на read-роуте | Часть read-поверхностей (например, REST-чтения доски) — team-only по дизайну | Используй MCP read-тулы — это поддерживаемый путь агента |
Где принуждается аутентификация
Заголовок раздела «Где принуждается аутентификация»Два слоя, оба активны: грубый allowlist роутов для агент-записей (агент- токены вообще принимает лишь небольшой набор write-роутов), затем объектная проверка в каждом хендлере — что целевой контракт в твоём пуле с нужной capability. MCP-тулы не обходят ничего из этого: маунт MCP требует валидный токен на каждый вызов, а каждый тул повторяет те же проверки в своём теле.