# Documentación de AgentBouncer

> Verifica solicitudes firmadas de agentes de IA y aplica políticas de acceso específicas del proyecto.

Versión de la documentación: 0.1.1

Canonical portal: https://agentbouncer.io/es/docs

Canonical Markdown: https://agentbouncer.io/es/docs.md

## Índice de documentación

- [Descripción general de AgentBouncer](#overview): Verifica solicitudes firmadas de agentes de IA y aplica políticas de acceso específicas del proyecto.
- [Inicio rápido](#quickstart): Crea un proyecto, copia una clave de API y protege un endpoint.
- [Conceptos fundamentales](#core-concepts): Comprende los proyectos, las claves de API, las claves de firma, los proveedores y las políticas.
- [Crear y administrar proyectos](#projects): Configura el límite de confianza de una aplicación o un servidor MCP.
- [Claves de API del proyecto](#api-keys): Autentica tu servidor cuando llame a la API de AgentBouncer.
- [Integración con la API REST](#rest-api): Llama a AgentBouncer desde cualquier lenguaje o framework de backend.
- [SDK de JavaScript y TypeScript](#sdk): Verifica solicitudes firmadas y aplica la decisión final de la política de AgentBouncer.
- [App Router de Next.js](#nextjs): Protege una ruta de Next.js conservando la URL externa de la solicitud.
- [Next.js sin el SDK](#manual-nextjs): Envía una carga útil mínima de verificación directamente a la API REST.
- [Integración con Express](#express): Protege rutas de Express mediante el endpoint REST de verificación.
- [Proteger herramientas MCP](#mcp): Aplica las decisiones de AgentBouncer antes de ejecutar operaciones MCP.
- [Claves de firma del proyecto](#project-signing-keys): Crea identidades para agentes que pertenecen directamente a tu proyecto.
- [Registrar un proveedor de agentes](#providers): Publica una identidad de proveedor y un directorio de claves públicas.
- [Modos de política](#policies): Elige cómo afectan al acceso la identidad verificada y los datos de confianza.
- [Políticas personalizadas](#custom-policies): Crea reglas detalladas de autorización y denegación.
- [Respuesta de verificación](#response): Comprende los campos devueltos por la API de verificación.
- [Motivos y errores](#errors): Motivos habituales de verificación y decisiones de política.
- [Eventos de verificación](#events): Supervisa el tráfico real e investiga las decisiones de autorización.
- [Recomendaciones de seguridad](#security): Despliega AgentBouncer sin filtrar secretos ni debilitar la verificación.
- [Solución de problemas](#troubleshooting): Diagnostica problemas de firma, URL, directorio de claves y políticas.
- [Lista de comprobación para producción](#production-checklist): Revisa la integración antes de activar políticas de bloqueo.

<a id="overview"></a>

## Descripción general de AgentBouncer

Verifica solicitudes firmadas de agentes de IA y aplica políticas de acceso específicas del proyecto.

AgentBouncer verifica las firmas de mensajes HTTP enviadas por agentes de IA, resuelve la clave pública del firmante, evalúa la política de tu proyecto y devuelve una decisión final de acceso.

> **La regla de integración más importante**
>
> Usa allowed como decisión final de autorización. verified informa del resultado criptográfico, mientras que allowed informa de la decisión efectiva de la política del proyecto.

| verified | allowed | Significado |
| --- | --- | --- |
| true | true | La firma es válida y la solicitud está permitida. |
| true | false | La firma es válida, pero la política del proyecto ha denegado el acceso. |
| false | true | La solicitud no se verificó, pero fue permitida por MONITOR_ONLY u otra configuración permisiva. |
| false | false | La solicitud no superó la verificación y se denegó el acceso. |

- Verifica firmas de mensajes HTTP RFC 9421.
- Resuelve claves públicas de proveedores y claves propiedad del proyecto.
- Aplica niveles de confianza, puntuaciones de confianza, acciones, herramientas y reglas personalizadas.
- Protege herramientas MCP, API, operaciones de pago y flujos de trabajo autónomos.
- Registra eventos de verificación para análisis e investigación de incidentes.

<a id="quickstart"></a>

## Inicio rápido

Crea un proyecto, copia una clave de API y protege un endpoint.

1. **Crea un proyecto** — Abre el panel de AgentBouncer, crea un proyecto e introduce el origen o host del servicio que quieres proteger.
2. **Comienza en modo de solo supervisión** — Usa MONITOR_ONLY durante la primera fase de integración. Las solicitudes seguirán ejecutándose mientras AgentBouncer registra cuáles se habrían bloqueado.
3. **Copia la clave de API del proyecto** — La clave de API autentica tu backend cuando llama a la API de verificación de AgentBouncer. No es una clave de firma de agente.
4. **Envía la URL original de la solicitud y los encabezados de firma** — La URL debe coincidir con la URL que firmó el agente. Conserva Signature, Signature-Input y Signature-Agent.
5. **Autoriza mediante allowed** — Rechaza la solicitud únicamente cuando allowed sea false.

### Verificar una solicitud mediante 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"
  }'

```

### Aplicar la decisión final

```typescript

const verification = await verifyWithAgentBouncer(request);

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

// Continúa con la operación protegida.
return runProtectedTool();

```

<a id="core-concepts"></a>

## Conceptos fundamentales

Comprende los proyectos, las claves de API, las claves de firma, los proveedores y las políticas.

| Concepto | Finalidad |
| --- | --- |
| Proyecto | Una aplicación, API, servidor MCP, origen o límite de confianza protegido. |
| Clave de API del proyecto | Autentica tu backend al llamar a /api/v1/verify. |
| Clave de firma del proyecto | Identifica y firma solicitudes de uno de tus propios agentes. |
| Proveedor | Un proveedor externo registrado de agentes de IA con una identidad de firma y un directorio de claves públicas. |
| Clave del proveedor | Una clave pública descubierta en el directorio de firmas de mensajes HTTP del proveedor. |
| Evento de verificación | Un registro inmutable del resultado criptográfico, la decisión de la política, el firmante, el riesgo y los metadatos de la solicitud. |
| Política | Reglas que convierten la información de verificación y confianza en allowed=true o allowed=false. |

> **Las claves de API y las claves de firma son diferentes**
>
> La clave de API del proyecto autoriza las llamadas de tu servidor a AgentBouncer. Una clave de firma está en posesión de un agente y firma la solicitud HTTP original.

<a id="projects"></a>

## Crear y administrar proyectos

Configura el límite de confianza de una aplicación o un servidor MCP.

1. **Crea el proyecto** — Elige un nombre descriptivo, como MCP de producción, API de pago o Automatización interna.
2. **Configura el origen** — Usa el origen público al que llaman los agentes. Las URL internas de despliegue o de proxy inverso no deben sustituir la URL externa firmada.
3. **Elige una política** — Comienza con MONITOR_ONLY, revisa los eventos de verificación y después cambia a BLOCK_UNKNOWN o a una política más estricta.
4. **Crea claves de firma del proyecto si es necesario** — Usa claves del proyecto para agentes internos, clientes de desarrollo e integraciones propiedad del proyecto.
5. **Revisa los eventos** — Inspecciona verified, allowed, reason, el tipo de firmante, el proveedor, la clave del proyecto, la acción, la herramienta, el riesgo y los detalles de la política.

> **Límites de proyecto recomendados**
>
> Usa proyectos separados para producción y desarrollo. Considera usar proyectos separados cuando las aplicaciones tengan requisitos de confianza o autorización sustancialmente diferentes.

<a id="api-keys"></a>

## Claves de API del proyecto

Autentica tu servidor cuando llame a la API de AgentBouncer.

Las claves de API del proyecto usan el prefijo ab_live_ y solo deben almacenarse en tu backend. Nunca las expongas en JavaScript del navegador, repositorios públicos o variables de entorno del lado del cliente.

### .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

```

- Almacena las claves de producción en el administrador de secretos de tu proveedor de alojamiento.
- Rota una clave si se registró o se confirmó accidentalmente en el repositorio.
- No envíes la clave de API al agente de IA entrante.
- No confundas la clave de API de AgentBouncer con una JWK privada de firma.

<a id="rest-api"></a>

## Integración con la API REST

Llama a AgentBouncer desde cualquier lenguaje o framework de backend.

### 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"
}

```

| Campo | Obligatorio | Descripción |
| --- | --- | --- |
| url | Sí | La URL externa exacta cuya solicitud fue firmada. |
| method | Recomendado | El método HTTP original. El valor predeterminado es GET. |
| headers | Recomendado | Encabezados de la solicitud original usados para verificar la firma. Los campos de firma también pueden proporcionarse mediante signature, signatureInput y signatureAgent. |
| signature | Condicional | El valor del encabezado Signature. Es obligatorio si no está incluido en headers. |
| signatureInput | Condicional | El valor del encabezado Signature-Input. Es obligatorio si no está incluido en headers. |
| signatureAgent | No | El valor de campo estructurado Signature-Agent. También puede incluirse en headers. |
| expectedTag | No | La etiqueta de intención esperada por el endpoint protegido. |
| action | No | Una operación semántica como tools:call, products:read, checkout u orders:write. |
| tool | No | La herramienta MCP o capacidad de la aplicación a la que se está accediendo. |
| userAgent | No | El User-Agent del solicitante original para análisis. |

> **Conserva la URL firmada**
>
> No sustituyas la URL pública de destino por la URL del endpoint de verificación de AgentBouncer, una URL interna del contenedor o una URL de proxy inverso.

<a id="sdk"></a>

## SDK de JavaScript y TypeScript

Verifica solicitudes firmadas y aplica la decisión final de la política de AgentBouncer.

### Instalación

```bash

npm install @agentbouncer/sdk

```

### Crear un cliente

```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,
  });

```

> **Constructor de clase**
>
> El SDK también exporta AgentBouncer. new AgentBouncer(options) y createAgentBouncer(options) crean el mismo cliente.

> **Configura el origen público detrás de un proxy**
>
> Si request.url contiene una URL interna de despliegue o de proxy inverso, configura publicOrigin con el origen visible externamente que firman los agentes. Como alternativa, puedes pasar targetUrl en cada llamada a verify().

### verify()

```typescript

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

if (!verification.allowed) {
  return new Response(
    "Acceso del agente denegado",
    {
      status: verification.verified
        ? 403
        : 401,
    }
  );
}

// Continúa con la operación protegida.

```

### 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(
      "Acceso del agente denegado",
      {
        status:
          error.verification.verified
            ? 403
            : 401,
      }
    );
  }

  if (
    error instanceof AgentBouncerError
  ) {
    return new Response(
      "La verificación del agente no está disponible",
      {
        status: 503,
      }
    );
  }

  throw error;
}

```

> **Semántica de los métodos del SDK**
>
> verify() devuelve el resultado completo de la verificación. require() lanza AgentBouncerDeniedError cuando allowed es false. Los fallos de red, tiempo de espera, autenticación de API y respuesta mal formada lanzan AgentBouncerError.

<a id="nextjs"></a>

## App Router de Next.js

Protege una ruta de Next.js conservando la URL externa de la solicitud.

### 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(
    "Falta AGENTBOUNCER_API_KEY"
  );
}

if (!publicOrigin) {
  throw new Error(
    "Falta 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
        : "Berlín";

    return NextResponse.json({
      ok: true,
      city,
      weather: {
        temperatureC: 21,
        conditions: "Despejado",
      },
      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(
      "La verificación de AgentBouncer ha fallado",
      {
        requestId,
        error,
      }
    );

    return NextResponse.json(
      {
        ok: false,
        error:
          "agentbouncer_unavailable",
        message:
          error instanceof
          AgentBouncerError
            ? error.message
            : "No se pudo verificar la solicitud.",
        requestId,
      },
      {
        status: 503,
      }
    );
  }
}

```

> **No uses la condición de autorización antigua**
>
> No uses if (!verification.verified || !verification.allowed). Esto bloquea incorrectamente las solicitudes permitidas por MONITOR_ONLY o allowUnsigned.

<a id="manual-nextjs"></a>

## Next.js sin el SDK

Envía una carga útil mínima de verificación directamente a la API REST.

### Recopilación mínima de encabezados

```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 devolvió HTTP ${response.status}.`
    );
  }

  if (
    !result ||
    typeof result.verified !== "boolean" ||
    typeof result.allowed !== "boolean"
  ) {
    throw new Error(
      "AgentBouncer devolvió una respuesta no válida."
    );
  }

  return result;
}

```

### Llamar al endpoint de verificación

```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(
      "La autenticación con la API de AgentBouncer ha fallado."
    );
  }

  return result;
}

```

<a id="express"></a>

## Integración con Express

Protege rutas de Express mediante el endpoint REST de verificación.

```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);
  }
}

```

<a id="mcp"></a>

## Proteger herramientas MCP

Aplica las decisiones de AgentBouncer antes de ejecutar operaciones MCP.

Configura action como tools:call y tool con el nombre de la herramienta MCP. Esto hace que los eventos de verificación y las reglas de política personalizadas sean específicos de la operación solicitada.

### Patrón de autorización 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: "Este agente no tiene permiso para llamar a la herramienta.",
      },
    ],
  };
}

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

  case "catalog":
    return searchCatalog(toolArguments);

  case "checkout":
    return createCheckout(toolArguments);

  default:
    throw new Error("Herramienta MCP desconocida");
}

```

| Operación | Acción sugerida | Herramienta sugerida |
| --- | --- | --- |
| Leer un recurso MCP | resources:read | nombre del recurso |
| Enumerar herramientas | tools:list | * |
| Llamar a una herramienta | tools:call | nombre de la herramienta |
| Leer productos | products:read | catalog |
| Crear un proceso de pago | checkout:create | checkout |
| Enviar un pedido | orders:create | orders |

<a id="project-signing-keys"></a>

## Claves de firma del proyecto

Crea identidades para agentes que pertenecen directamente a tu proyecto.

1. **Emite una clave del proyecto** — Abre la pestaña Claves de agente del proyecto y crea una clave descriptiva, como Agente MCP de producción o CRM interno.
2. **Guarda la JWK privada** — La clave privada se muestra una sola vez. Almacénala en el administrador de secretos del agente.
3. **Conserva la identidad pública** — AgentBouncer almacena la JWK pública, el ID de clave, la identidad signature-agent, los ámbitos y la configuración de políticas.
4. **Firma las solicitudes** — Usa la JWK privada para generar los encabezados Signature y Signature-Input de la URL de destino exacta.
5. **Revoca las claves comprometidas** — Elimina o revoca inmediatamente una clave del proyecto si su JWK privada queda expuesta.

### Ejemplo de variables de entorno

```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":"..."}'

```

<a id="providers"></a>

## Registrar un proveedor de agentes

Publica una identidad de proveedor y un directorio de claves públicas.

1. **Crea el proveedor** — Elige un slug estable, el nombre del proveedor, el sitio web, el origen de signature-agent y la URL del directorio.
2. **Publica el JWKS público** — Expón las claves públicas en el directorio configurado de firmas de mensajes HTTP.
3. **Actualiza las claves** — Solicita a AgentBouncer que cargue y valide el directorio.
4. **Verifica el dominio del proveedor** — Publica el registro DNS TXT de AgentBouncer o el archivo de verificación.
5. **Firma solicitudes de producción** — Usa una clave privada que corresponda a una clave pública activa del directorio.

### Ejemplo de documento JWKS

```json

{
  "keys": [
    {
      "kty": "OKP",
      "crv": "Ed25519",
      "kid": "provider-key-2026-01",
      "alg": "EdDSA",
      "use": "sig",
      "x": "PUBLIC_KEY_MATERIAL"
    }
  ]
}

```

### Ubicación pública recomendada

```text

https://agent.example/.well-known/http-message-signatures-directory/jwks.json

```

> **Nunca publiques la JWK privada**
>
> En el directorio del proveedor solo deben incluirse las propiedades públicas de la JWK. La propiedad privada d debe permanecer secreta.

<a id="policies"></a>

## Modos de política

Elige cómo afectan al acceso la identidad verificada y los datos de confianza.

| Modo | Comportamiento |
| --- | --- |
| MONITOR_ONLY | Registra los fallos de verificación y de política, pero permite la solicitud. |
| BLOCK_UNKNOWN | Bloquea las solicitudes sin firma y las identidades desconocidas. |
| ALLOW_TIER_1_ONLY | Permite únicamente el nivel de proveedor con la máxima confianza. |
| ALLOW_TIER_1_AND_2 | Permite proveedores de confianza de nivel 1 y nivel 2. |
| CUSTOM | Evalúa reglas de proveedor, nivel, clave del proyecto, acción y herramienta. Las reglas DENY coincidentes tienen prioridad sobre las reglas ALLOW coincidentes; en caso contrario, se aplica defaultEffect. |

> **Despliegue recomendado**
>
> Comienza con MONITOR_ONLY, inspecciona el tráfico real, define acciones y herramientas, prueba las claves del proyecto y solo entonces activa el bloqueo.

<a id="custom-policies"></a>

## Políticas personalizadas

Crea reglas detalladas de autorización y denegación.

### Ejemplo de política personalizada

```json

{
  "version": 1,
  "defaultEffect": "DENY",
  "rules": [
    {
      "id": "rule_allow_tier_1_read",
      "name": "Permitir lecturas de catálogo de nivel 1",
      "enabled": true,
      "effect": "ALLOW",
      "subject": {
        "type": "PROVIDER_TIER",
        "tiers": ["TIER_1"]
      },
      "actions": ["products:read"],
      "tools": ["catalog"]
    },
    {
      "id": "rule_deny_external_checkout",
      "name": "Denegar pagos externos",
      "enabled": true,
      "effect": "DENY",
      "subject": {
        "type": "ANY_PROVIDER"
      },
      "actions": ["checkout:create"],
      "tools": ["checkout"]
    }
  ]
}

```

- Las reglas DENY tienen prioridad sobre las reglas ALLOW.
- Un array actions vacío coincide con cualquier acción.
- Un array tools vacío coincide con cualquier herramienta.
- El comodín * coincide con cualquier acción o herramienta.
- Si ninguna regla coincide, se aplica defaultEffect.
- Usa PROJECT_KEY para seleccionar claves concretas de agentes internos.

<a id="response"></a>

## Respuesta de verificación

Comprende los campos devueltos por la API de verificación.

```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": "Agente MCP de producción",
      "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": "Permitir agente meteorológico",
      "effect": "ALLOW"
    },
    "defaultEffectApplied": false
  }
}

```

> **Detección de repeticiones**
>
> Una firma válida no demuestra por sí sola que la solicitud no se haya repetido. Hasta que se active el almacenamiento de repeticiones o la validación de nonces, checks.replay se muestra como unknown.

| Campo | Significado |
| --- | --- |
| verified | Indica si la verificación criptográfica de la identidad se completó correctamente. |
| allowed | La decisión final de autorización después de aplicar la política del proyecto. |
| reason | El motivo efectivo de la denegación, o null cuando se permite el acceso. |
| checks | Resultados individuales de la firma, la marca de tiempo, la repetición, el proveedor, la clave del proyecto y la política. unknown significa que no se realizó una comprobación o que no había información suficiente. |
| agent | La identidad resuelta del proveedor o de la clave del proyecto. |
| risk | La puntuación y el nivel de riesgo calculados. |
| policy | El modo de política, la regla coincidente y el motivo de bloqueo hipotético. |

<a id="errors"></a>

## Motivos y errores

Motivos habituales de verificación y decisiones de política.

| Motivo | Descripción |
| --- | --- |
| unauthorized | La clave de API del proyecto de AgentBouncer falta o no es válida. |
| invalid_request | Falta un campo obligatorio en la carga útil de verificación. |
| invalid_url | url no es una URL absoluta de destino válida. |
| no_signature | Falta Signature o Signature-Input. |
| no_keyid | Signature-Input no contiene keyid. |
| unknown_keyid | No se encontró ninguna clave activa del proyecto o del proveedor. |
| not_yet_valid | La hora de creación de la firma está en el futuro. |
| expired | La firma ha caducado. |
| window_too_long | El intervalo de la firma entre created y expires supera el máximo permitido. |
| bad_signature | La verificación criptográfica ha fallado. |
| unknown_provider | No se reconoce al proveedor de la clave. |
| provider_blocked | El proveedor está suspendido, bloqueado, marcado como fraudulento o revocado. |
| provider_not_trusted | El proyecto requiere un proveedor de confianza. |
| unsupported_tag | La etiqueta de intención de la firma no es compatible. |
| tag_mismatch | La etiqueta real de la firma no coincide con expectedTag. |
| tier_too_low | El proveedor no cumple el nivel requerido. |
| trust_score_too_low | La puntuación de confianza del proveedor está por debajo del umbral del proyecto. |
| project_keys_disabled | Las claves de firma propiedad del proyecto están desactivadas. |
| custom_policy_denied | Una regla DENY personalizada coincidente ha rechazado la solicitud. |
| custom_policy_no_match | Ninguna regla personalizada ha coincidido y el efecto predeterminado es DENY. |

<a id="events"></a>

## Eventos de verificación

Supervisa el tráfico real e investiga las decisiones de autorización.

- Filtra los eventos por día, semana, mes, todo el periodo o fechas personalizadas.
- Compara las solicitudes verificadas con las solicitudes permitidas.
- Usa allowed, no verified, al etiquetar un evento como aceptado o rechazado.
- Inspecciona el nivel, estado, puntuación de confianza y puntuación de abuso del proveedor, además del riesgo, la acción y la herramienta.
- Revisa wouldBlockReason para las solicitudes permitidas por MONITOR_ONLY.
- Exporta los datos de los eventos como CSV para analizarlos sin conexión.

| verified | allowed | Etiqueta de interfaz recomendada |
| --- | --- | --- |
| true | true | Permitido |
| true | false | Denegado por la política |
| false | true | Permitido en modo de supervisión |
| false | false | Verificación fallida |

<a id="security"></a>

## Recomendaciones de seguridad

Despliega AgentBouncer sin filtrar secretos ni debilitar la verificación.

- Mantén las claves de API de AgentBouncer en el servidor.
- Mantén las JWK privadas de firma en un administrador de secretos.
- Publica únicamente las propiedades públicas de las JWK.
- Usa HTTPS para las URL de destino, las identidades signature-agent y los directorios de claves.
- Conserva la URL visible externamente y el método HTTP originales.
- No reenvíes Authorization, Cookie, Set-Cookie, x-api-key ni credenciales de proxy en las cargas útiles de verificación.
- Excluye los encabezados de proxy inverso y observabilidad, salvo que se firmen intencionadamente.
- Usa intervalos cortos de validez para las firmas.
- Revoca las claves comprometidas del proyecto y del proveedor.
- Comienza los cambios de política en MONITOR_ONLY antes de aplicarlos de forma obligatoria.

> **Integridad del cuerpo de la solicitud**
>
> AgentBouncer verifica la firma de mensajes HTTP sobre los componentes cubiertos de la solicitud que se proporcionan a la API de verificación. Las aplicaciones que dependan de un Content-Digest firmado también deben comprobar que el resumen coincida con el cuerpo recibido por el endpoint protegido.

<a id="troubleshooting"></a>

## Solución de problemas

Diagnostica problemas de firma, URL, directorio de claves y políticas.

| Problema | Qué comprobar |
| --- | --- |
| Encabezado Signature no válido | Asegúrate de que Signature, Signature-Input y Signature-Agent estén incluidos exactamente una vez cada uno. |
| bad_signature | Compara la URL firmada, el método, la autoridad, los componentes cubiertos, la clave pública y el resumen del contenido. |
| unknown_keyid | Confirma que la clave del proyecto esté activa o actualiza el directorio de claves públicas del proveedor. |
| tag_mismatch | Compara expectedTag con la etiqueta incluida en Signature-Input. |
| custom_policy_no_match | Comprueba el tipo de sujeto, el ID de la clave del proyecto, el nivel del proveedor, la acción, la herramienta y defaultEffect. |
| MONITOR_ONLY sigue bloqueando | Asegúrate de que tu aplicación compruebe únicamente verification.allowed. |
| @authority incorrecto | Usa el host externo que firmó el agente, no un host interno de despliegue. |

### Condición de autorización correcta

```typescript

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

```

### Condición de autorización incorrecta

```typescript

// Incorrecto: bloquea las solicitudes de MONITOR_ONLY.
if (!verification.verified || !verification.allowed) {
  return new Response("Denegado", {
    status: 403,
  });
}

```

<a id="production-checklist"></a>

## Lista de comprobación para producción

Revisa la integración antes de activar políticas de bloqueo.

- La clave de API de AgentBouncer está almacenada únicamente en el servidor.
- El proyecto de producción usa el origen público correcto.
- La aplicación envía la URL de destino firmada exacta.
- Los encabezados de firma se reenvían exactamente una vez.
- Los encabezados confidenciales y de infraestructura están excluidos.
- La condición de autorización comprueba allowed.
- Las acciones y los nombres de herramientas MCP están definidos.
- Se ha revisado el tráfico de MONITOR_ONLY.
- Los proveedores conocidos y las claves del proyecto se resuelven correctamente.
- Las políticas personalizadas tienen un efecto predeterminado intencionado.
- Las claves privadas de firma están almacenadas en un administrador de secretos.
- Los procedimientos de revocación y rotación de claves están documentados.
- Se han probado las exportaciones de eventos de verificación.
