# 03 · Autenticación

Su servidor MCP es un endpoint expuesto a internet que puede leer y escribir en sus sistemas.
La autorización es opcional en el estándar; **en este contrato no lo es**.

Hay dos niveles admitidos. Ambos son servidor a servidor: no hay usuario final, ni pantallas
de consentimiento, ni OAuth de terceros.

## Nivel 1 · OAuth 2.1 (recomendado)

Su servidor actúa como **servidor de recursos** OAuth 2.1. Asixto obtiene un token por
credenciales de cliente y lo presenta en cada petición.

Requisitos:

| # | Requisito | Exigencia |
|---|---|---|
| 1 | Publicar **metadatos de recurso protegido** (RFC 9728) en `/.well-known/oauth-protected-resource` | **DEBE** en el nivel 1 |
| 2 | Responder **401** con `WWW-Authenticate` indicando el `scope` requerido cuando falta o es inválida la credencial | **DEBE** |
| 3 | **Validar la audiencia** del token (RFC 8707): rechazar todo token que no fue emitido para su servidor | **DEBE** |
| 4 | Exponer descubrimiento del servidor de autorización (RFC 8414 u OpenID Connect Discovery) | **DEBE** |
| 5 | Soportar documentos de metadatos de cliente (Client ID Metadata Documents) | DEBERÍA |

El registro dinámico de cliente (RFC 7591) quedó **obsoleto** en la revisión 2026-07-28 y se
mantiene solo por compatibilidad. No lo requiera.

### Con el SDK de TypeScript

El paquete de Express trae las piezas hechas:

```ts
import {
  createMcpExpressApp,
  requireBearerAuth,
  mcpAuthMetadataRouter,
  getOAuthProtectedResourceMetadataUrl,
} from '@modelcontextprotocol/express';

const app = createMcpExpressApp();

// Publica los metadatos de recurso protegido (RFC 9728)
app.use(mcpAuthMetadataRouter({ /* su servidor de autorización */ }));

// Protege el endpoint MCP: valida Authorization: Bearer … con su verificador
app.use('/mcp', requireBearerAuth({ verifier: miVerificadorDeTokens }));
```

`getOAuthProtectedResourceMetadataUrl(serverUrl)` construye la URL que debe anunciar en la
cabecera `WWW-Authenticate`.

### Respuesta esperada sin credencial

```http
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://mcp.suempresa.com/.well-known/oauth-protected-resource", scope="mcp:tools"
```

## Nivel 2 · Token rotable (mínimo aceptable)

Un token opaco emitido por usted, presentado como `Authorization: Bearer …`.

| Requisito | Exigencia |
|---|---|
| Longitud ≥ 32 bytes de entropía | **DEBE** |
| Caducidad declarada | **DEBE** |
| Dos credenciales activas simultáneas durante la rotación | **DEBE** |
| Rotación sin intervención de Asixto | **DEBE** |
| 401 (no 403 ni 500) cuando falta o es inválido | **DEBE** |

Se admite para incorporación rápida y entornos de prueba. El registro la guardará cifrada y nunca
la escribe en trazas.

## Defensa en profundidad

Además del token:

- **TLS obligatorio** con certificado válido. Sin excepciones, tampoco en pruebas.
- **Lista blanca de dominio**: el Gateway llamará únicamente a la URL registrada del tenant.
- **Restricción por origen** (opcional): puede limitar por el rango de direcciones del Gateway.
- **Validación de cabecera Host** si su servidor también escucha en local: el SDK trae
  `hostHeaderValidation` para protección ante DNS rebinding.

## Reglas duras de aislamiento

1. **Asixto nunca reenvía a su servidor un token de la plataforma Asixto.** Su servidor solo
   recibe la credencial que usted mismo emitió. Esto evita que un servidor externo pueda actuar
   en nombre del tenant contra la plataforma.
2. **Un servidor registrado queda ligado a un único tenant.** No debe responder por otra
   empresa, y el Gateway no comparte su catálogo con otros tenants.
3. **Sin secretos en las respuestas ni en los mensajes de error.** El texto de error puede
   terminar leído en voz alta en una llamada.

## Lista de verificación

- [ ] Petición sin `Authorization` → 401 con `WWW-Authenticate`.
- [ ] Token de otra audiencia → 401.
- [ ] Token caducado → 401 (no 500).
- [ ] Metadatos de recurso protegido accesibles y coherentes con la URL del servidor.
- [ ] Rotación probada con las dos credenciales activas.
- [ ] Ningún token en logs de su lado.
