Saltar a contenido

Autenticación y scopes

Cada endpoint protegido del contrato de lectura de Tarno está controlado por una clave de API. Esta guía cubre cómo presentar la clave, los dos scopes, el ciclo de vida de la clave y la semántica exacta de 401 / 403 / 429 — todo en concordancia con los handlers en vivo.

El encabezado X-API-Key

Envía tu clave en el encabezado de solicitud X-API-Key en cada llamada a una ruta protegida:

curl -sS "$TARNO_BASE_URL/v1/brands?limit=1" -H "X-API-Key: $TARNO_API_KEY"

La clave es una cadena opaca emitida por el operador (marcador de posición <API_KEY> en esta documentación). El servidor la verifica en cada solicitud; la clave en crudo nunca se registra en logs.

El servidor MCP usa el mismo encabezado X-API-Key, enviado por solicitud sobre el transporte Streamable HTTP — consulta la guía de MCP. (Para el transporte stdio, la clave se lee de la variable de entorno TARNO_API_KEY en su lugar.)

Rutas públicas que no necesitan clave

/health, /docs y /metrics son las únicas rutas que funcionan sin clave. Todo lo que está bajo /v1 requiere una.

Scopes

Una clave lleva un conjunto de scopes que determinan qué partes del contrato puede leer:

Scope Otorga acceso a
brands:read El contrato de marcas: GET /v1/brands, GET /v1/brands/:nroSolicitud.
insights:read El contrato operacional: GET /v1/freshness, GET /v1/sync-runs.
watch:read Lecturas de Vigilancia: GET /v1/watch, GET /v1/watch/:id, GET /v1/watch/:id/hits.
watch:write Escrituras de Vigilancia: POST /v1/watch, PATCH /v1/watch/:id, DELETE /v1/watch/:id.

Un arreglo de scopes vacío no tiene restricción — una clave emitida sin scopes recibe todos los scopes de lectura. Una clave con un arreglo de scopes no vacío recibe solo los scopes listados; llamar a una ruta cuyo scope requerido está ausente se rechaza con 403 forbidden.

Los scopes watch:* requieren además que la clave tenga una org dueña (consumerId); consulta la guía de Vigilancia para la tenencia, la entrega dual y la firma de los webhooks.

Las herramientas de MCP siguen la misma regla: tanto search_brands como get_brand_detail requieren brands:read (o una clave sin restricción, con scopes vacíos).

Ciclo de vida de la clave (gestionado por el operador)

Las claves se crean, rotan, revocan y expiran por el operador a través de la CLI de administración. Como integrador, tú no gestionas las claves por tu cuenta; solicitas los cambios a tu operador.

  • Rotar — el operador te emite una clave nueva y da de baja la antigua. Cambia el valor X-API-Key que tu cliente envía; sin cambios de código más allá del secreto.
  • Revocar — una clave revocada deja de funcionar de inmediato: las llamadas posteriores devuelven 401 unauthorized, exactamente como con una clave desconocida.
  • Expiración — una clave puede llevar una fecha de expiración. Una vez pasada la expiración se trata como inválida y devuelve 401 unauthorized. Pídele a tu operador que la reemita antes de la expiración para evitar caídas.

Cada clave también pertenece a un consumidor y lleva una cuota mensual (ver más abajo).

Semántica de estados

Estos son los resultados exactos que producen las capas de autenticación y cuota:

401 unauthorized

Se devuelve cuando la clave está ausente, malformada, es desconocida o está revocada/expirada.

{ "error": { "code": "unauthorized", "message": "Missing or invalid API key", "requestId": "..." } }

403 forbidden

Se devuelve cuando la clave es válida y está activa, pero le falta el scope que la ruta requiere. El mensaje nombra el scope faltante:

{ "error": { "code": "forbidden", "message": "API key lacks required scope: insights:read", "requestId": "..." } }

429 quota_exceeded

Se devuelve cuando la cuota mensual de la clave está agotada. Lleva un encabezado Retry-After con los segundos hasta que la ventana de cuota se reinicia:

HTTP/1.1 429 Too Many Requests
Retry-After: 1209600

{ "error": { "code": "quota_exceeded", "message": "Monthly quota exceeded", "requestId": "..." } }

429 rate_limited

Existen dos límites de tasa, ambos aditivos a la cuota mensual y ambos devuelven 429 con un encabezado Retry-After (segundos a esperar):

  • Ráfaga por clave (code: rate_limited) — un segundo nivel por hash de la clave que acota a un solo inquilino: por defecto 300 solicitudes cada 60 s. Aplica de forma idéntica en REST y en el MCP (ambos transportes comparten el mismo contador), es independiente de la IP del cliente (por lo que un pool de IP rotatorio no lo esquiva) y no cambia el esquema del contrato /v1 — es una nueva condición 429 puramente aditiva.

```text HTTP/1.1 429 Too Many Requests Retry-After: 42

{ "error": { "code": "rate_limited", "message": "Too many requests (per-key burst limit)", "requestId": "..." } } ```

  • Defensa anti-inundación por IP (code: rate_limited) — un límite por IP de cliente (por defecto 100 solicitudes/minuto) que frena una avalancha previa a la autenticación (claves rotatorias). Es independiente del nivel por clave.

Acción del consumidor: respeta el Retry-After y reintenta después de ese número de segundos. La cuota mensual (quota_exceeded) y ambos límites de tasa (rate_limited) aplican de forma idéntica en REST y en el MCP, ya que ambos transportes se autentican contra las mismas claves y comparten los mismos contadores.

El sobre de error uniforme { error: { code, message, requestId } } se describe en la guía de primeros pasos. Usa requestId (también reflejado en el encabezado de respuesta x-request-id) al reportar un problema a tu operador.

CORS y acceso desde el navegador

IRIS es server-side-only por defecto: la clave X-API-Key es una credencial de servidor y nunca debe incrustarse en un cliente de navegador. Por eso, de forma predeterminada la API no emite ningún encabezado Access-Control-Allow-Origin — un fetch desde el navegador de un tercero no puede leer las respuestas. Este es el comportamiento por defecto y no cambia nada respecto a versiones previas.

El acceso cross-origin desde navegador es opt-in por despliegue mediante la variable de entorno IRIS_CORS_ALLOWLIST (lista de orígenes exactos separados por comas):

IRIS_CORS_ALLOWLIST=https://app.tarno.cl,https://docs.tarno.cl
  • Vacía / sin definir → sin CORS (sin encabezado Access-Control-Allow-Origin) — el default no-op.
  • Con orígenes → sólo esos orígenes exactos reciben el encabezado Access-Control-Allow-Origin (nunca un comodín ni reflejo arbitrario del Origin); no se envían credenciales (credentials:false). Las peticiones preflight OPTIONS de esos orígenes se responden con los encabezados de permiso.

El servidor MCP no usa CORS. El MCP es un transporte servidor-a-servidor (lo consumen agentes de IA por la red, no un fetch de navegador), así que CORS —una salvaguarda del navegador— no aplica ahí.

Ver también

  • Primeros pasos — URL base, primera llamada, paginación, sobre de error.
  • Conecta tu agente de IA (MCP) — misma clave, mismos scopes, sobre MCP.
  • La referencia OpenAPI en vivo en /docs — seguridad y esquema por endpoint.