Phase 13 - Lesson 16

Seguridad de MCP II — OAuth 2.1, Indicadores de Recurso, Escopos Incrementales

This lesson includes a graded coding exercise that runs in your browser, unlocked with lifetime access.

Los servidores MCP remotos necesitan autorización, no solo autenticación. La especificación del 25-11-2025 se alinea con OAuth 2.1 + PKCE + indicadores de recurso (RFC 8707) + metadados de recurso protegido (RFC 9728). SEP-835 agrega consentimiento de alcance incremental con autorización step-up en 403 WWW-Authenticate. Esta lección implementa el flujo de step-up como una máquina de estados para que pueda ver cada paso.

Tipo: Build Lenguajes: Python (stdlib, simulador de máquina de estados OAuth) Prerrequisitos: Fase 13 · 09 (transports), Fase 13 · 15 (security I) Tiempo: ~75 minutos

Objetivos de Aprendizaje

  • Distinguir las responsabilidades del servidor de recursos de las del servidor de autorización.
  • Recorrer el flujo de código de autorización OAuth 2.1 protegido por PKCE.
  • Usar resource (RFC 8707) y metadados de recurso protegido (RFC 9728) para prevenir ataques de diputado confuso.
  • Implementar autorización step-up: el servidor responde 403 con WWW-Authenticate solicitando un alcance mayor; el cliente vuelve a solicitar el consentimiento del usuario y reintenta.

O Problema

Las primeras versiones de MCP (pre-2025) enviaban servidores remotos con claves API ad-hoc o incluso sin autenticación. La especificación del 25-11-2025 cierra esa brecha con un perfil OAuth 2.1 completo.

Tres necesidades del mundo real:

  • Servidores remotos comunes. El usuario instala un servidor MCP remoto que accede a su Notion / GitHub / Gmail. OAuth 2.1 con PKCE es el formato adecuado.
  • Escalada de alcance. Un servidor de notas que tiene permitido notes:read puede necesitar más adelante notes:write para una acción específica. En lugar de rehacer todo el flujo, step-up (SEP-835) solicita el alcance adicional.
  • Prevención de diputado confuso. El cliente tiene un token con alcance de audiencia para el Servidor A. El Servidor A es malicioso e intenta presentar el token al Servidor B. Los indicadores de recurso (RFC 8707) vinculan el token a su audiencia prevista.

OAuth 2.1 no es nuevo. Lo que es nuevo es el perfil de MCP: flujos específicos requeridos (solo código de autorización + PKCE; sin flujo implícito ni credenciales de cliente por defecto), indicadores de recurso obligatorios en cada solicitud de token y metadados de recurso protegido publicados para que los clientes sepan a dónde ir.

El Concepto

Roles

  • Cliente. El cliente MCP (Claude Desktop, Cursor, etc.).
  • Servidor de recursos. El servidor MCP (notas, GitHub, Postgres, etc.).
  • Servidor de autorización. Emite tokens. Puede ser el mismo servicio que el servidor de recursos o un IdP independiente (Auth0, Keycloak, Cognito).

En el perfil de MCP, los servidores de recursos y de autorización PUEDEN ser el mismo host, pero DEBERÍAN distinguirse por URLs.

Código de autorización + PKCE

El flujo:

  1. El cliente genera code_verifier (aleatorio) y code_challenge (SHA256).
  2. El cliente redirecciona al usuario a /authorize?response_type=code&client_id=...&redirect_uri=...&scope=notes:read&code_challenge=...&resource=https://notes.example.com.
  3. El usuario da su consentimiento. El servidor de autorización redirecciona a redirect_uri?code=....
  4. El cliente hace un POST a /token?grant_type=authorization_code&code=...&code_verifier=...&resource=....
  5. El servidor de autorización valida el hash del verificador contra el desafío almacenado y emite un token de acceso.
  6. El cliente utiliza el token: Authorization: Bearer ... en cada solicitud al servidor de recursos.

PKCE evita los ataques de interceptación de código de autorización. Los indicadores de recurso evitan que el token sea válido en otros lugares.

Metadados de recurso protegido (RFC 9728)

El servidor de recursos publica un documento en .well-known/oauth-protected-resource:

{
  "resource": "https://notes.example.com",
  "authorization_servers": ["https://auth.example.com"],
  "scopes_supported": ["notes:read", "notes:write", "notes:delete"]
}

El cliente descubre el servidor de autorización a partir del servidor de recursos. Reduce la configuración: el cliente solo necesita la URL del recurso.

Indicadores de recurso (RFC 8707)

El parámetro resource en la solicitud de token vincula la audiencia prevista del token. El token emitido contiene aud: "https://notes.example.com". Otro servidor MCP que recibe este token verifica aud y lo rechaza.

Modelo de alcance

Los alcances (scopes) son cadenas separadas por espacios. Convenciones comunes de MCP:

  • notes:read, notes:write, notes:delete
  • admin:* para capacidades administrativas (usar con moderación)
  • profile:read para identidad

La selección del alcance debe seguir el principio de menor privilegio: solicite lo que necesita ahora, y realice step-up cuando necesite más.

Autorización step-up (SEP-835)

El usuario concede notes:read. Más tarde, le pide al agente que elimine una nota. El servidor responde:

HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer error="insufficient_scope",
    scope="notes:delete", resource="https://notes.example.com"

El cliente ve el error de insufficient_scope, muestra al usuario un diálogo de consentimiento para el alcance adicional, realiza un mini flujo OAuth para este y vuelve a intentar la solicitud con el nuevo token.

Validación de audiencia del token

Cada solicitud: el servidor verifica que token.aud == self.resource_url. Discrepancia = 401. Esto detiene la reutilización de tokens entre servidores.

Tokens de corta duración y rotación

Los tokens de acceso DEBERÍAN ser de corta duración (1 hora por defecto). Los tokens de actualización (refresh tokens) rotan en cada actualización. El cliente maneja la actualización silenciosa en segundo plano.

Sin transferencia de tokens

Los servidores de muestreo (Fase 13 · 11) NO DEBEN pasar el token del cliente a otros servicios. La solicitud de muestreo es el límite.

Prevención de diputado confuso

El token se vincula a aud. El cliente se vincula a client_id. Cada solicitud se valida contra ambos. La especificación prohíbe explícitamente el antiguo patrón de "pasar el token" que era común en los ecosistemas de herramientas remotas previos a MCP.

Descubrimiento de ID de cliente

Cada cliente MCP publica sus metadados en una URL fija. Los servidores de autorización pueden obtener el documento de metadados del cliente para descubrir las URIs de redirecionamiento y la información de contacto. Esto elimina el registro manual del cliente.

Gateways y OAuth

La Fase 13 · 17 muestra cómo un gateway empresarial maneja OAuth: el gateway contiene las credenciales para los servidores upstream, los tokens para el cliente son emitidos por el gateway y los tokens upstream nunca salen del gateway. Esto invierte el modelo de confianza: los usuarios se autentican con el gateway una vez; el gateway maneja N autorizaciones de servidores.

Úsalo

code/main.py simula el flujo completo de step-up de OAuth 2.1 como una máquina de estados. Implementa:

  • Generación de code-verifier / challenge de PKCE.
  • Flujo de código de autorización con indicador de recurso.
  • Endpoint de metadados de recurso protegido.
  • Validación de token con verificación de audiencia.
  • Step-up en caso de insufficient_scope.

No hay servidor HTTP en esta lección; la máquina de estados se ejecuta en memoria para que pueda rastrear cada paso. La lección de gateway de la Fase 13 · 17 lo conecta a un transporte real.

Envíalo

Esta lección produce outputs/skill-oauth-scope-planner.md. Dado un servidor MCP remoto con herramientas, la skill diseña el conjunto de alcances, las reglas de vinculación y la política de step-up.

Ejercicios

  1. Ejecute code/main.py. Rastree el flujo de step-up de dos alcances. Observe qué pasos se repiten en el step-up.

  2. Agregue rotación de tokens de actualización: cada actualización emite un nuevo token de actualización e invalida el antiguo. Simule el uso de un token de actualización robado después de la rotación y confirme que falla.

  3. Implemente el endpoint de metadados de recurso protegido como una respuesta HTTP real utilizando el http.server de la biblioteca estándar. Copie el endpoint /mcp de la Lección 09.

  4. Diseñe una jerarquía de alcances para un servidor MCP de GitHub: leer repositorio, escribir PR, aprobar PR, fusionar PR, administrador. Utilice step-up entre cada nivel.

  5. Lea la RFC 8707 y la RFC 9728. Identifique el único campo en 9728 que MCP usa de manera diferente al ejemplo de la RFC. (Pista: tiene que ver con scopes_supported.)

Términos clave

Término Lo que dice la gente Lo que realmente significa
OAuth 2.1 "OAuth moderno" RFC consolidada que exige PKCE y proíbe el flujo implícito
PKCE "Prueba de posesión" Code verifier + challenge que evitan la interceptación de códigos de autorización
Indicador de recurso "Audiencia del token" Parámetro resource de la RFC 8707 que vincula el token a un solo servidor
Metadados de recurso protegido "Doc de descubrimiento" RFC 9728 .well-known/oauth-protected-resource
Autorización step-up "Consentimiento incremental" Flujo de SEP-835 para agregar alcances bajo demanda
insufficient_scope "403 con WWW-Authenticate" Señal del servidor para volver a dar consentimiento para un alcance mayor
Diputado confuso "Reutilización de tokens entre servicios" Ataque en el que un portador de confianza reenvía un token de forma inapropiada
Token de corta duración "TTL del token de acceso" Portador que expira rápidamente; el token de actualización lo renueva
Jerarquía de alcances "Pila de menor privilegio" Conjunto de alcances graduados con step-up entre niveles
Metadados del ID del cliente "Doc de descubrimiento del cliente" URL en la que el cliente publica sus propios metadados de OAuth

Lectura adicional

0 lifetime access. Curriculum based on AI Engineering from Scratch by Rohit Ghumare (MIT, used under attribution).