ID-JAG — механизм авторизации AI-агентов, использующий обмен токенами (RFC 8693, RFC 7523) для безопасного делегирования прав. Узнайте, как внедрить принцип наименьших привилегий в цепочке вызовов агентов.
Представьте: AI-агент, подключённый к внутренним системам, получает права наравне с человеком. Одна ошибка — и последствия могут быть катастрофическими. ID-JAG (Identity Assertion JWT Authorization Grant) решает именно эту проблему: он позволяет агенту действовать от имени пользователя, но с минимально необходимыми правами и строгим аудитом.
ID-JAG — это механизм авторизации, при котором каждый вызов API сопровождается доказательством: «конкретный пользователь в конкретный момент разрешил агенту выполнить это действие». Он основан на двух RFC — обмене токенами (RFC 8693) и JWT Bearer (RFC 7523) — и уже реализован в системах Athenz и Okta, а также цитируется в спецификации MCP.
Ранее мы разбирали OAuth2 PKCE — он защищает клиентское приложение от перехвата кода авторизации. Но PKCE решает проблему одношаговой аутентификации «пользователь → приложение». ID-JAG же работает в многошаговой цепочке: пользователь → шлюз AI → MCP-сервер → ресурсный сервер. Каждый шаг требует доказательства полномочий, и ID-JAG позволяет обменивать токены с сужением прав на каждой границе доверия.
В отличие от PKCE, ID-JAG не требует всплывающих окон для каждого нового сервиса: авторизация консолидируется при входе через SSO, а затем агент использует выпущенный identity assertion для получения токенов без участия пользователя.
Определяет протокол обмена одного токена на другой. Пример запроса:
POST /token
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
subject_token=<Identity Assertion JWT>
subject_token_type=urn:ietf:params:oauth:token-type:jwt
requested_token_type=urn:ietf:params:oauth:token-type:access_token
scope=read:ordersПараметр subject_token содержит делегируемый токен, requested_token_type — желаемый тип, а scope позволяет сузить права прямо при обмене.
Позволяет использовать JWT напрямую как учётные данные OAuth2 без дополнительного обмена:
POST /token
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
assertion=<Signed Identity Assertion JWT>Сервер авторизации проверяет подпись JWT с помощью публичного ключа IdP и, если поля aud, scope, exp корректны, выдаёт Access Token без повторного согласия пользователя.
Identity Assertion JWT обычно содержит:
{
"iss": "https://enterprise.idp.example.com/v1",
"sub": "alice@company.com",
"aud": "https://api.service.example.com",
"exp": 1773839486,
"iat": 1773825086,
"jti": "abc123-7dc6-42ab-b326-uniqueid",
"scope": "read:orders write:tickets"
}Поле jti — уникальный идентификатор для предотвращения повторного использования.
Рассмотрим архитектуру из туториала id-jag-the-hard-way (Athenz как сервер авторизации):
На каждом шаге токен обменивается, а его область действия сужается. Токен шлюза не может быть использован напрямую для доступа к ресурсному серверу — MCP-сервер принудительно перевыпускает его. В итоговом токене фиксируются и sub (пользователь), и act (агент), что сохраняет полную цепочку аудита.
Самое красивое в ID-JAG — что наименьшие привилегии реализуются архитектурно, а не через code review. Рассмотрим пример из моей реализации id-jag-mcp на Go:
| Инструмент | Athenz Scope |
|---|---|
| get_k8s_docs | api:role.docs-getter |
| delete_k8s_doc | api:role.docs-deleter |
| post_k8s_doc | api:role.docs-poster |
Когда MCP-сервер получает запрос, он не передаёт токен шлюза напрямую — он всегда запрашивает у Athenz ZTS новый токен ровно с тем скоупом, который нужен для данного инструмента. Даже если токен шлюза содержит права на чтение и удаление, MCP-сервер запросит только api:role.docs-getter для чтения. Это делает нарушение принципа наименьших привилегий архитектурно невозможным.
Исходный MCP-сервер в id-jag-the-hard-way был написан на TypeScript + Express с самописным JSON-RPC 2.0. Я хотел проверить две вещи: воспроизводима ли логика обмена токенов на другом языке и как работает официальный modelcontextprotocol/go-sdk. В результате я полностью заменил протокольный слой на Go SDK, сохранив ту же логику маппинга скоупов и mTLS-обмена. mTLS-клиент написан с нуля, без зависимости от официального Go-клиента Athenz.
Попробуйте развернуть мою реализацию id-jag-mcp из репозитория kkdai/id-jag-mcp. Это поможет вам понять, как работает обмен токенов на практике и как внедрить принцип наименьших привилегий в ваши AI-агенты. Начните с запуска тестового окружения с Athenz и Keycloak, затем поэкспериментируйте с вызовом разных инструментов — вы увидите, как сужаются права на каждом шаге.
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →