Документация разработчика

Проверяйте AI-агентов до предоставления доступа к API

Интегрируйте криптографическую проверку, политики доверия, ключи подписи, авторизацию MCP и аналитику.

Введение

Обзор AgentBouncer

Проверяйте подписанные запросы ИИ-агентов и применяйте политики доступа конкретного проекта.

AgentBouncer проверяет подписи HTTP-сообщений, отправленные ИИ-агентами, определяет открытый ключ подписанта, оценивает политику вашего проекта и возвращает итоговое решение о доступе.

Самое важное правило интеграции

Используйте allowed как итоговое решение об авторизации. Поле verified сообщает результат криптографической проверки, а allowed — фактическое решение политики проекта.

verifiedallowedЗначение
truetrueПодпись действительна, и запрос разрешён.
truefalseПодпись действительна, но политика проекта запретила доступ.
falsetrueЗапрос не прошёл проверку, но был разрешён режимом MONITOR_ONLY или другой разрешающей настройкой.
falsefalseЗапрос не прошёл проверку, и доступ был запрещён.
  • Проверяйте подписи HTTP-сообщений по стандарту RFC 9421.
  • Получайте открытые ключи провайдеров и ключи, принадлежащие проекту.
  • Применяйте уровни доверия, оценки доверия, действия, инструменты и пользовательские правила.
  • Защищайте инструменты MCP, API, операции оформления заказа и автономные рабочие процессы.
  • Сохраняйте события проверки для аналитики и расследования инцидентов.
Введение

Быстрый старт

Создайте проект, скопируйте API-ключ и защитите конечную точку.

  1. 1

    Создайте проект

    Откройте панель управления AgentBouncer, создайте проект и укажите origin или хост сервиса, который вы хотите защитить.

  2. 2

    Начните с режима мониторинга

    На первом этапе интеграции используйте MONITOR_ONLY. Запросы продолжат выполняться, а AgentBouncer будет фиксировать, какие из них были бы заблокированы.

  3. 3

    Скопируйте API-ключ проекта

    API-ключ аутентифицирует ваш сервер при обращении к API проверки AgentBouncer. Он не является ключом подписи агента.

  4. 4

    Передайте исходный URL запроса и заголовки подписи

    URL должен совпадать с URL, который подписал агент. Сохраняйте заголовки Signature, Signature-Input и Signature-Agent.

  5. 5

    Авторизуйте запрос с помощью allowed

    Отклоняйте запрос только в том случае, если allowed имеет значение false.

Проверка запроса через REST
bash
curl -X POST https://agentbouncer.io/api/v1/verify \
  -H "Authorization: Bearer ab_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://merchant.example/api/mcp/weather",
    "method": "POST",
    "headers": {
      "signature": "sig1=:BASE64_SIGNATURE:",
      "signature-input": "sig1=(\"@authority\" \"signature-agent\");created=176000;expires=176000030;keyid=\"KEY_ID\";tag=\"web-bot-auth\"",
      "signature-agent": "\"https://agent.example\"",
      "content-type": "application/json"
    },
    "expectedTag": "web-bot-auth",
    "action": "tools:call",
    "tool": "weather"
  }'
Применение итогового решения
typescript
const verification = await verifyWithAgentBouncer(request);

if (!verification.allowed) {
  return Response.json(
    {
      ok: false,
      error: "agent_access_denied",
      verification,
    },
    {
      status: verification.verified ? 403 : 401,
    }
  );
}

// Продолжите выполнение защищённой операции.
return runProtectedTool();
Основные понятия

Ключевые понятия

Узнайте, что такое проекты, API-ключи, ключи подписи, провайдеры и политики.

ПонятиеНазначение
ПроектЗащищённое приложение, API, MCP-сервер, origin или граница доверия.
API-ключ проектаАутентифицирует ваш сервер при обращении к /api/v1/verify.
Ключ подписи проектаИдентифицирует один из ваших собственных агентов и подписывает его запросы.
ПровайдерЗарегистрированный внешний провайдер ИИ-агентов с идентификатором подписи и каталогом открытых ключей.
Ключ провайдераОткрытый ключ, найденный в каталоге подписей HTTP-сообщений провайдера.
Событие проверкиНеизменяемая запись о результате криптографической проверки, решении политики, подписанте, риске и метаданных запроса.
ПолитикаПравила, преобразующие информацию о проверке и доверии в allowed=true или allowed=false.

API-ключи и ключи подписи — это разные ключи

API-ключ проекта разрешает вашему серверу обращаться к AgentBouncer. Ключ подписи хранится у агента и используется для подписания исходного HTTP-запроса.

Панель управления

Создание проектов и управление ими

Настройте границу доверия для приложения или MCP-сервера.

  1. 1

    Создайте проект

    Выберите понятное название, например «Production MCP», «Checkout API» или «Внутрення автоматизация».

  2. 2

    Укажите origin

    Используйте публичный origin, к которому обращаются агенты. URL обратного прокси и внутренних развёртываний не должны заменять внешний подписанный URL.

  3. 3

    Выберите политику

    Начните с MONITOR_ONLY, изучите события проверки, а затем перейдите к BLOCK_UNKNOWN или более строгой политике.

  4. 4

    При необходимости создайте ключи подписи проекта

    Используйте ключи проекта для внутренних агентов, клиентов разработки и интеграций, принадлежащих проекту.

  5. 5

    Просматривайте события

    Проверяйте поля verified, allowed, reason, тип подписанта, провайдера, ключ проекта, действие, инструмент, риск и сведения о политике.

Рекомендуемые границы проектов

Используйте отдельные проекты для production- и development-сред. Также создавайте отдельные проекты для приложений с существенно различающимися требованиями к доверию или авторизации.

Панель управления

API-ключи проекта

Аутентифицируйте сервер при обращении к API AgentBouncer.

API-ключи проекта имеют префикс ab_live_ и должны храниться только на сервере. Никогда не размещайте их в браузерном JavaScript, публичных репозиториях или клиентских переменных окружения.

.env.local
bash
AGENTBOUNCER_API_KEY=ab_live_YOUR_API_KEY
AGENTBOUNCER_PUBLIC_ORIGIN=https://merchant.example
AGENTBOUNCER_VERIFY_URL=https://agentbouncer.io/api/v1/verify
  • Храните production-ключи в менеджере секретов вашего хостинг-провайдера.
  • Ротируйте ключ, если он случайно попал в журнал или репозиторий.
  • Не отправляйте API-ключ входящему ИИ-агенту.
  • Не путайте API-ключ AgentBouncer с приватным JWK подписи.
Интеграция

Интеграция с REST API

Вызывайте AgentBouncer из любого языка или серверного фреймворка.

POST /api/v1/verify
http
POST /api/v1/verify HTTP/1.1
Host: agentbouncer.io
Authorization: Bearer ab_live_YOUR_API_KEY
Content-Type: application/json

{
  "url": "https://merchant.example/api/mcp/weather",
  "method": "POST",
  "headers": {
    "signature": "sig1=:...:",
    "signature-input": "sig1=(...);created=...;expires=...;keyid=\"...\";tag=\"web-bot-auth\"",
    "signature-agent": "\"https://agent.example\""
  },
  "expectedTag": "web-bot-auth",
  "action": "tools:call",
  "tool": "weather",
  "userAgent": "ExampleAgent/1.0"
}
ПолеОбязательностьОписание
urlДаТочный внешний URL, запрос к которому был подписан.
methodРекомендуетсяИсходный HTTP-метод. По умолчанию используется GET.
headersРекомендуетсяИсходные заголовки запроса, используемые для проверки подписи. Поля подписи также можно передать через signature, signatureInput и signatureAgent.
signatureУсловноЗначение заголовка Signature. Обязательно, если оно не включено в headers.
signatureInputУсловноЗначение заголовка Signature-Input. Обязательно, если оно не включено в headers.
signatureAgentНетЗначение структурированного поля Signature-Agent. Его также можно включить в headers.
expectedTagНетТег назначения, ожидаемый защищённой конечной точкой.
actionНетСемантическая операция, например tools:call, products:read, checkout или orders:write.
toolНетИнструмент MCP или возможность приложения, к которой выполняется обращение.
userAgentНетИсходный User-Agent отправителя запроса для аналитики.

Сохраняйте подписанный URL

Не заменяйте публичный целевой URL адресом конечной точки проверки AgentBouncer, внутренним URL контейнера или URL обратного прокси.

Интеграция

SDK для JavaScript и TypeScript

Проверяйте подписанные запросы и применяйте итоговое решение политики AgentBouncer.

Установка
bash
npm install @agentbouncer/sdk
Создание клиента
typescript
import {
  createAgentBouncer,
} from "@agentbouncer/sdk";

export const agentBouncer =
  createAgentBouncer({
    apiKey:
      process.env.AGENTBOUNCER_API_KEY!,
    publicOrigin:
      process.env.AGENTBOUNCER_PUBLIC_ORIGIN,
    verifyUrl:
      process.env.AGENTBOUNCER_VERIFY_URL,
  });

Конструктор класса

SDK также экспортирует AgentBouncer. Вызовы new AgentBouncer(options) и createAgentBouncer(options) создают один и тот же тип клиента.

Настройте публичный origin при работе за прокси

Если request.url содержит внутренний URL развёртывания или обратного прокси, задайте в publicOrigin внешний origin, который подписывают агенты. В качестве альтернативы можно передавать targetUrl при каждом вызове verify().

verify()
typescript
const verification =
  await agentBouncer.verify({
    request,
    expectedTag: "web-bot-auth",
    action: "tools:call",
    tool: "weather",
  });

if (!verification.allowed) {
  return new Response(
    "Доступ агента запрещён",
    {
      status: verification.verified
        ? 403
        : 401,
    }
  );
}

// Продолжите выполнение защищённой операции.
require()
typescript
import {
  AgentBouncerDeniedError,
  AgentBouncerError,
} from "@agentbouncer/sdk";

try {
  const verification =
    await agentBouncer.require({
      request,
      expectedTag: "web-bot-auth",
      action: "tools:call",
      tool: "weather",
    });

  return runWeatherTool({
    agent: verification.agent,
  });
} catch (error) {
  if (
    error instanceof
    AgentBouncerDeniedError
  ) {
    return new Response(
      "Доступ агента запрещён",
      {
        status:
          error.verification.verified
            ? 403
            : 401,
      }
    );
  }

  if (
    error instanceof AgentBouncerError
  ) {
    return new Response(
      "Сервис проверки агента недоступен",
      {
        status: 503,
      }
    );
  }

  throw error;
}

Семантика методов SDK

Метод verify() возвращает полный результат проверки. Метод require() выбрасывает AgentBouncerDeniedError, если allowed имеет значение false. Ошибки сети, тайм-ауты, ошибки аутентификации API и некоректные ответы вызывают AgentBouncerError.

Интеграция

Next.js App Router

Защитите маршрут Next.js, сохранив внешний URL запроса.

src/lib/agentbouncer-client.ts
typescript
import {
  createAgentBouncer,
} from "@agentbouncer/sdk";

const apiKey =
  process.env.AGENTBOUNCER_API_KEY;

const publicOrigin =
  process.env.AGENTBOUNCER_PUBLIC_ORIGIN;

if (!apiKey) {
  throw new Error(
    "Не задан AGENTBOUNCER_API_KEY"
  );
}

if (!publicOrigin) {
  throw new Error(
    "Не задан AGENTBOUNCER_PUBLIC_ORIGIN"
  );
}

export const agentBouncer =
  createAgentBouncer({
    apiKey,
    publicOrigin,
    verifyUrl:
      process.env.AGENTBOUNCER_VERIFY_URL,
  });
src/app/api/mcp/weather/route.ts
typescript
import {
  AgentBouncerDeniedError,
  AgentBouncerError,
} from "@agentbouncer/sdk";
import {
  NextRequest,
  NextResponse,
} from "next/server";
import {
  agentBouncer,
} from "@/lib/agentbouncer-client";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";

export async function POST(
  req: NextRequest
) {
  const requestId = crypto.randomUUID();

  try {
    const verification =
      await agentBouncer.require({
        request: req,
        expectedTag: "web-bot-auth",
        action: "tools:call",
        tool: "weather",
      });

    const body = await req
      .json()
      .catch(() => ({}));

    const city =
      typeof body.city === "string"
        ? body.city
        : "Berlin";

    return NextResponse.json({
      ok: true,
      city,
      weather: {
        temperatureC: 21,
        conditions: "Ясно",
      },
      agent: verification.agent,
      requestId,
    });
  } catch (error) {
    if (
      error instanceof
      AgentBouncerDeniedError
    ) {
      return NextResponse.json(
        {
          ok: false,
          error: "mcp_access_denied",
          reason:
            error.verification.reason,
          requestId,
        },
        {
          status:
            error.verification.verified
              ? 403
              : 401,
        }
      );
    }

    console.error(
      "Не удалось выполнить проверку AgentBouncer",
      {
        requestId,
        error,
      }
    );

    return NextResponse.json(
      {
        ok: false,
        error:
          "agentbouncer_unavailable",
        message:
          error instanceof
          AgentBouncerError
            ? error.message
            : "Не удалось проверить запрос.",
        requestId,
      },
      {
        status: 503,
      }
    );
  }
}

Не используйте старую проверку доступа

Не используйте if (!verification.verified || !verification.allowed). Такая проверка ошибочно блокирует запросы, разрешённые режимом MONITOR_ONLY или настройкой allowUnsigned.

Интеграция

Next.js без SDK

Отправляйте минимальную полезную нагрузку проверки непосредственно в REST API.

Минимальный сбор заголовков
typescript
import type {
  NextRequest,
} from "next/server";
import {
  pickVerificationHeaders,
} from "./pick-verification-headers";

function resolvePublicTargetUrl(
  req: NextRequest
) {
  const publicOrigin =
    process.env
      .AGENTBOUNCER_PUBLIC_ORIGIN;

  if (!publicOrigin) {
    return req.nextUrl.toString();
  }

  return new URL(
    `${req.nextUrl.pathname}${req.nextUrl.search}`,
    publicOrigin
  ).toString();
}

export async function verifyAgentRequest(
  req: NextRequest,
  options?: {
    expectedTag?: string;
    action?: string;
    tool?: string;
  }
) {
  const targetUrl =
    resolvePublicTargetUrl(req);

  const response = await fetch(
    process.env.AGENTBOUNCER_VERIFY_URL ??
      "https://agentbouncer.io/api/v1/verify",
    {
      method: "POST",
      headers: {
        Authorization:
          `Bearer ${process.env.AGENTBOUNCER_API_KEY}`,
        "Content-Type": "application/json",
        Accept: "application/json",
      },
      body: JSON.stringify({
        url: targetUrl,
        method: req.method,
        headers:
          pickVerificationHeaders(req),
        expectedTag:
          options?.expectedTag ?? null,
        action:
          options?.action ?? null,
        tool:
          options?.tool ?? null,
        userAgent:
          req.headers.get("user-agent"),
      }),
      cache: "no-store",
    }
  );

  const result = await response
    .json()
    .catch(() => null);

  if (!response.ok) {
    throw new Error(
      result?.detail ||
        result?.reason ||
        `AgentBouncer вернул HTTP ${response.status}.`
    );
  }

  if (
    !result ||
    typeof result.verified !== "boolean" ||
    typeof result.allowed !== "boolean"
  ) {
    throw new Error(
      "AgentBouncer вернул некоректный ответ."
    );
  }

  return result;
}
Вызов конечной точки проверки
typescript
import type { NextRequest } from "next/server";
import { pickVerificationHeaders } from "./pick-verification-headers";

export async function verifyAgentRequest(
  req: NextRequest,
  options?: {
    expectedTag?: string;
    action?: string;
    tool?: string;
  }
) {
  const targetUrl = req.nextUrl.toString();

  const response = await fetch(
    process.env.AGENTBOUNCER_VERIFY_URL ??
      "https://agentbouncer.io/api/v1/verify",
    {
      method: "POST",
      headers: {
        Authorization:
          `Bearer ${process.env.AGENTBOUNCER_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        url: targetUrl,
        method: req.method,
        headers: pickVerificationHeaders(req),
        expectedTag: options?.expectedTag ?? null,
        action: options?.action ?? null,
        tool: options?.tool ?? null,
        userAgent: req.headers.get("user-agent"),
      }),
      cache: "no-store",
    }
  );

  const result = await response.json();

  if (!response.ok && response.status === 401) {
    throw new Error(
      "Не удалось пройти аутентификацию API AgentBouncer."
    );
  }

  return result;
}
Интеграция

Интеграция с Express

Защищайте маршруты Express с помощью REST API проверки.

typescript
import type {
  NextFunction,
  Request,
  Response,
} from "express";

export async function requireVerifiedAgent(
  req: Request,
  res: Response,
  next: NextFunction
) {
  try {
    const protocol =
      req.headers["x-forwarded-proto"] || req.protocol;

    const host =
      req.headers["x-forwarded-host"] ||
      req.headers.host;

    const targetUrl =
      `${protocol}://${host}${req.originalUrl}`;

    const verifyResponse = await fetch(
      "https://agentbouncer.io/api/v1/verify",
      {
        method: "POST",
        headers: {
          Authorization:
            `Bearer ${process.env.AGENTBOUNCER_API_KEY}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          url: targetUrl,
          method: req.method,
          headers: {
            signature: req.headers.signature,
            "signature-input":
              req.headers["signature-input"],
            "signature-agent":
              req.headers["signature-agent"],
            "content-type":
              req.headers["content-type"],
            "content-digest":
              req.headers["content-digest"],
          },
          expectedTag: "web-bot-auth",
          action: "api:call",
        }),
      }
    );

    const verification = await verifyResponse.json();

    if (!verification.allowed) {
      res.status(verification.verified ? 403 : 401).json({
        ok: false,
        error: "agent_access_denied",
        verification,
      });

      return;
    }

    res.locals.agentVerification = verification;
    next();
  } catch (error) {
    next(error);
  }
}
Интеграция

Защита инструментов MCP

Применяйте решения AgentBouncer до выполнения операций MCP.

Укажите для action значение tools:call, а для tool — имя инструмента MCP. Благодаря этому события проверки и правила пользовательской политики будут относиться к конкретной запрашиваемой операции.

Шаблон авторизации MCP
typescript
const verification = await agentBouncer.verify({
  request,
  expectedTag: "web-bot-auth",
  action: "tools:call",
  tool: toolName,
});

if (!verification.allowed) {
  return {
    isError: true,
    content: [
      {
        type: "text",
        text: "Этому агенту запрещён вызов инструмента.",
      },
    ],
  };
}

switch (toolName) {
  case "weather":
    return getWeather(toolArguments);

  case "catalog":
    return searchCatalog(toolArguments);

  case "checkout":
    return createCheckout(toolArguments);

  default:
    throw new Error("Неизвестный инструмент MCP");
}
ОперацияРекомендуемое действиеРекомендуемый инструмент
Чтение ресурса MCPresources:readимя ресурса
Получение списка инструментовtools:list*
Вызов инструментаtools:callимя инструмента
Чтение товаровproducts:readcatalog
Создание оформления заказаcheckout:createcheckout
Отправка заказаorders:createorders
Идентификаторы агентов

Ключи подписи проекта

Создавайте идентификаторы для агентов, непосредственно принадлежащих вашему проекту.

  1. 1

    Выпустите ключ проекта

    Откройте вкладку Agent keys проекта и создайте ключ с понятным названием, например «Production MCP agent» или «Internal CRM».

  2. 2

    Сохраните приватный JWK

    Приватный ключ показывается только один раз. Сохраните его в менеджере секретов агента.

  3. 3

    Сохраните публичный идентификатор

    AgentBouncer хранит открытый JWK, идентификатор ключа, идентификатор Signature-Agent, области доступа и конфигурацию политики.

  4. 4

    Подписывайте запросы

    Используйте приватный JWK для создания заголовков Signature и Signature-Input для точного целевого URL.

  5. 5

    Отзывайте скомпрометированные ключи

    Немедленно удалите или отзовите ключ проекта, если его приватный JWK был раскрыт.

Пример переменных окружения
bash
AGENT_KEY_ID=YOUR_KEY_ID
AGENT_SIGNATURE_AGENT=https://agentbouncer.io/project-agents/PROJECT_ID/KEY_ID
AGENT_PRIVATE_JWK='{"kty":"OKP","crv":"Ed25519","x":"...","d":"..."}'
Идентификаторы агентов

Регистрация провайдера агентов

Опубликуйте идентификатор провайдера и каталог открытых ключей.

  1. 1

    Создайте провайдера

    Выберите постоянный slug, название провайдера, веб-сайт, origin Signature-Agent и URL каталога.

  2. 2

    Опубликуйте открытый JWKS

    Разместите открытые ключи в настроенном каталоге подписей HTTP-сообщений.

  3. 3

    Обновите ключи

    Запросите у AgentBouncer загрузку и проверку каталога.

  4. 4

    Подтвердите домен провайдера

    Опубликуйте DNS TXT-запись AgentBouncer или файл подтверждения.

  5. 5

    Подписывайте production-запросы

    Используйте приватный ключ, соответствующий активному открытому ключу в каталоге.

Пример документа JWKS
json
{
  "keys": [
    {
      "kty": "OKP",
      "crv": "Ed25519",
      "kid": "provider-key-2026-01",
      "alg": "EdDSA",
      "use": "sig",
      "x": "PUBLIC_KEY_MATERIAL"
    }
  ]
}
Рекомендуемый публичный адрес
text
https://agent.example/.well-known/http-message-signatures-directory/jwks.json

Никогда не публикуйте приватный JWK

Каталог провайдера должен содержать только публичные свойства JWK. Приватное свойство d должно оставаться секретным.

Авторизация

Режимы политик

Выберите, как проверенный идентификатор и данные о доверии влияют на доступ.

РежимПоведение
MONITOR_ONLYРегистрирует ошибки проверки и политики, но разрешает запрос.
BLOCK_UNKNOWNБлокирует неподписанные запросы и неизвестные идентификаторы.
ALLOW_TIER_1_ONLYРазрешает доступ только провайдерам с наивысшим уровнем доверия.
ALLOW_TIER_1_AND_2Разрешает доступ доверенным провайдерам уровней Tier 1 и Tier 2.
CUSTOMОценивает правила провайдера, уровня доверия, ключа проекта, действия и инструмента. Совпавшие правила DENY имеют приоритет над совпавшими правилами ALLOW; если совпадений нет, применяется defaultEffect.

Рекомендуемый порядок внедрения

Начните с MONITOR_ONLY, изучите реальный трафик, определите действия и инструменты, протестируйте ключи проекта и только после этого включайте блокировку.

Авторизация

Пользовательские политики

Создавайте детальные разрешающие и запрещающие правила.

Пример пользовательской политики
json
{
  "version": 1,
  "defaultEffect": "DENY",
  "rules": [
    {
      "id": "rule_allow_tier_1_read",
      "name": "Разрешить Tier 1 чтение каталога",
      "enabled": true,
      "effect": "ALLOW",
      "subject": {
        "type": "PROVIDER_TIER",
        "tiers": ["TIER_1"]
      },
      "actions": ["products:read"],
      "tools": ["catalog"]
    },
    {
      "id": "rule_deny_external_checkout",
      "name": "Запретить внешнее оформление заказа",
      "enabled": true,
      "effect": "DENY",
      "subject": {
        "type": "ANY_PROVIDER"
      },
      "actions": ["checkout:create"],
      "tools": ["checkout"]
    }
  ]
}
  • Правила DENY имеют приоритет над правилами ALLOW.
  • Пустой массив actions соответствует любому действию.
  • Пустой массив tools соответствует любому инструменту.
  • Подстановочный символ * соответствует любому действию или инструменту.
  • Если ни одно правило не совпало, применяется defaultEffect.
  • Используйте PROJECT_KEY для выбора конкретных ключей внутренних агентов.
Справочник API

Ответ проверки

Изучите поля, возвращаемые API проверки.

json
{
  "verified": true,
  "allowed": true,
  "reason": null,
  "checks": {
    "signature": "valid",
    "timestamp": "valid",
    "replay": "unknown",
    "provider": "known",
    "policy": "matched"
  },
  "agent": {
    "type": "PROJECT_KEY",
    "provider": null,
    "providerSlug": null,
    "projectKey": {
      "id": "key_id",
      "name": "Production MCP agent",
      "scopes": []
    },
    "signatureAgent": "https://agentbouncer.io/project-agents/...",
    "keyid": "..."
  },
  "request": {
    "method": "POST",
    "path": "/api/mcp/weather",
    "tag": "web-bot-auth",
    "expectedTag": "web-bot-auth",
    "action": "tools:call",
    "tool": "weather"
  },
  "risk": {
    "score": 5,
    "level": "low"
  },
  "policy": {
    "mode": "CUSTOM",
    "wouldBlockReason": null,
    "matchedRule": {
      "id": "rule_allow_weather",
      "name": "Разрешить погодного агента",
      "effect": "ALLOW"
    },
    "defaultEffectApplied": false
  }
}

Обнаружение повторных запросов

Действительная подпись сама по себе не доказывает, что запрос не был воспроизведён повторно. Пока не включено хранилище защиты от повторов или проверка nonce, поле checks.replay возвращает unknown.

ПолеЗначение
verifiedУказывает, была ли успешно выполнена криптографическая проверка идентификатора.
allowedИтоговое решение об авторизации после применения политики проекта.
reasonФактическая причина отказа или null, если доступ разрешён.
checksОтдельные результаты проверки подписи, временной метки, повтора, провайдера, ключа проекта и политики. Значение unknown означает, что проверка не выполнялась или для неё не хватило информации.
agentОпределённый идентификатор провайдера или ключа проекта.
riskРассчитанная оценка и уровень риска.
policyРежим политики, совпавшее правило и гипотетическая причина блокировки.
Справочник API

Причины и ошибки

Распространённые причины результатов проверки и решений политики.

ПричинаОписание
unauthorizedAPI-ключ проекта AgentBouncer отсутствует или недействителен.
invalid_requestВ полезной нагрузке проверки отсутствует обязательное поле.
invalid_urlПоле url не является допустимым абсолютным целевым URL.
no_signatureОтсутствует заголовок Signature или Signature-Input.
no_keyidЗаголовок Signature-Input не содержит keyid.
unknown_keyidАктивный ключ проекта или провайдера не найден.
not_yet_validВремя создания подписи находится в будущем.
expiredСрок действия подписи истёк.
window_too_longПериод действия подписи от created до expires превышает допустимый максимум.
bad_signatureКриптографическая проверка завершилась неудачно.
unknown_providerПровайдер ключа не распознан.
provider_blockedПровайдер приостановлен, заблокирован, признан мошенническим или отозван.
provider_not_trustedПроект требует доверенного провайдера.
unsupported_tagТег назначения подписи не поддерживается.
tag_mismatchФактический тег подписи не соответствует expectedTag.
tier_too_lowПровайдер не соответствует требуемому уровню доверия.
trust_score_too_lowОценка доверия провайдера ниже порогового значения проекта.
project_keys_disabledКлючи подписи, принадлежащие проекту, отключены.
custom_policy_deniedСовпавшее пользовательское правило DENY отклонило запрос.
custom_policy_no_matchНи одно пользовательское правило не совпало, а эффект по умолчанию установлен в DENY.
Эксплуатация

События проверки

Отслеживайте реальный трафик и расследуйте решения об авторизации.

  • Фильтруйте события по дню, неделе, месяцу, всему периоду или произвольному диапазону дат.
  • Сравнивайте проверенные запросы с разрешёнными запросами.
  • При обозначении события как принятого или отклонённого используйте allowed, а не verified.
  • Проверяйте уровень и статус провайдера, оценку доверия, оценку злоупотреблений, риск, действие и инструмент.
  • Просматривайте wouldBlockReason для запросов, разрешённых режимом MONITOR_ONLY.
  • Экспортируйте данные событий в CSV для автономного анализа.
verifiedallowedРекомендуемая метка интерфейса
truetrueРазрешён
truefalseЗапрещён политикой
falsetrueРазрешён в режиме мониторинга
falsefalseПроверка не пройдена
Эксплуатация

Рекомендации по безопасности

Развёртывайте AgentBouncer без утечки секретов и ослабления проверки.

  • Храните API-ключи AgentBouncer на сервере.
  • Храните приватные JWK подписи в менеджере секретов.
  • Публикуйте только открытые свойства JWK.
  • Используйте HTTPS для целевых URL, идентификаторов Signature-Agent и каталогов ключей.
  • Сохраняйте исходный внешний URL и HTTP-метод.
  • Не передавайте Authorization, Cookie, Set-Cookie, x-api-key или учётные данные прокси в полезной нагрузке проверки.
  • Исключайте заголовки обратного прокси и наблюдаемости, если они не подписываются намеренно.
  • Используйте короткие периоды действия подписи.
  • Отзывайте скомпрометированные ключи проекта и провайдера.
  • Перед принудительным применением изменений политики сначала тестируйте их в режиме MONITOR_ONLY.

Целостность тела запроса

AgentBouncer проверяет подпись HTTP-сообщения по охватываемым компонентам запроса, переданным в API проверки. Приложения, использующие подписанный Content-Digest, также должны убедиться, что дайджест соответствует телу, полученному защищённой конечной точкой.

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

Устранение неполадок

Диагностируйте проблемы с подписью, URL, каталогом ключей и политикой.

ПроблемаЧто проверить
Некоректный заголовок SignatureУбедитесь, что Signature, Signature-Input и Signature-Agent переданы ровно по одному разу.
bad_signatureСравните подписанный URL, метод, authority, охватываемые компоненты, открытый ключ и дайджест содержимого.
unknown_keyidУбедитесь, что ключ проекта активен, или обновите каталог открытых ключей провайдера.
tag_mismatchСравните expectedTag с тегом в Signature-Input.
custom_policy_no_matchПроверьте тип субъекта, идентификатор ключа проекта, уровень провайдера, действие, инструмент и defaultEffect.
MONITOR_ONLY продолжает блокировать запросыУбедитесь, что приложение проверяет только verification.allowed.
Неверный @authorityИспользуйте внешний хост, который подписал агент, а не внутренний хост развёртывания.
Правильная проверка авторизации
typescript
if (!verification.allowed) {
  return Response.json(
    {
      ok: false,
      error: "agent_access_denied",
      verification,
    },
    {
      status: verification.verified ? 403 : 401,
    }
  );
}
Неправильная проверка авторизации
typescript
// Неправильно: блокирует запросы в режиме MONITOR_ONLY.
if (!verification.verified || !verification.allowed) {
  return new Response("Доступ запрещён", {
    status: 403,
  });
}
Эксплуатация

Контрольный список перед запуском

Проверьте интеграцию перед включением блокирующих политик.

  • API-ключ AgentBouncer хранится только на сервере.
  • Production-проект использует правильный публичный origin.
  • Приложение отправляет точный подписанный целевой URL.
  • Заголовки подписи передаются ровно по одному разу.
  • Конфиденциальные и инфраструктурные заголовки исключены.
  • Проверка авторизации использует allowed.
  • Действия и имена инструментов MCP заполнены.
  • Трафик MONITOR_ONLY был проанализирован.
  • Известные провайдеры и ключи проекта определяются правильно.
  • Пользовательские политики имеют намеренно выбранный эффект по умолчанию.
  • Приватные ключи подписи хранятся в менеджере секретов.
  • Процедуры отзыва и ротации ключей документированы.
  • Экспорт событий проверки протестирован.