HTTP Authentication

WWW-Authenticate

Es la cabecera HTTP con la que un servidor responde 401 Unauthorized para decirle al cliente cómo debe autenticarse. No es un mecanismo de login concreto: es el protocolo de negociación que anuncia qué esquema de credenciales acepta el recurso.

Estándar desde RFC 7235, es la base del discovery de autenticación en la web: el cliente no necesita conocer de antemano el método; lo aprende del propio reto del servidor.

El flujo de reto–respuesta

1
GET /recurso
El cliente pide un recurso protegido sin credenciales.
2
401 + WWW-Authenticate
El servidor rechaza y describe el esquema requerido en la cabecera.
3
Authorization: …
El cliente reintenta con la credencial del esquema indicado.
4
200 OK
El servidor valida y entrega el recurso.

El paso 2 es la clave: la cabecera WWW-Authenticate lleva el scheme(Basic, Digest, Bearer…) y parámetros como realm,scope o nonce. El cliente responde reflejando esa información en la cabecera Authorization.

Por qué el discovery ayuda a la web

Sin configuración previa. Un cliente genérico puede llegar a cualquier recurso, recibir un 401 y saber al instante qué credencial preparar.

Interoperabilidad. Navegadores, librerías HTTP y agentes hablan el mismo lenguaje. El servidor cambia su política de auth y los clientes se adaptan solos.

Evolución sin romper clientes. Con RFC 9728 el reto puede apuntar a un documento de metadatos, encadenando descubrimiento de servidores de autorización, scopes y endpoints. Esto es lo que hace viables ecosistemas como OAuth, OIDC, agentes y MCP.

Esquemas de autenticación

BasicRFC 7617No recomendado

Envía usuario y contraseña codificados en Base64 en cada petición. Base64 no es cifrado — cualquiera que intercepte la cabecera lee la contraseña en claro.

Reto del servidor
WWW-Authenticate: Basic realm="demo"
  • ·Reversible al instante: atob("dXNlcjpwYXNzd29yZA==") → "user:password".
  • ·Obliga a usar HTTPS siempre; sin TLS la credencial viaja expuesta.
  • ·No hay expiración ni revocación: la credencial vale hasta que cambie la contraseña.
  • ·El navegador muestra un diálogo nativo de usuario/contraseña.
Respuesta del cliente
Authorization: Basic dXNlcjpwYXNzd29yZA==
Compatible con
  • Todos los navegadores
  • curl / wget
  • Librerías HTTP estándar
DigestRFC 7616Heredado

Esquema desafío–respuesta: el servidor envía un nonce y el cliente responde con un hash, nunca con la contraseña. Mejora a Basic pero MD5 ya es débil.

Reto del servidor
WWW-Authenticate: Digest realm="demo", nonce="…", algorithm=MD5, qop="auth"
  • ·La contraseña nunca viaja por la red, solo un hash derivado.
  • ·El nonce mitiga ataques de repetición (replay).
  • ·qop="auth" protege también el método y la URI de la petición.
  • ·Sigue dependiendo de MD5/SHA-256; menos práctico que tokens para APIs.
Respuesta del cliente
Authorization: Digest username="user", realm="demo", nonce="…", uri="/demo/digest", response="…", qop=auth, nc=00000001, cnonce="…"
Compatible con
  • Todos los navegadores
  • curl / wget
  • Librerías HTTP con soporte Digest
BearerRFC 6750Recomendado para APIs

El cliente porta un token de acceso (a menudo un JWT) emitido por un servidor de autorización. "El que lo porta, lo usa" — por eso el token debe protegerse como una credencial.

Reto del servidor
WWW-Authenticate: Bearer
  realm="demo",
  scope="read write",
  error="invalid_token",
  error_description="El token ha expirado o es inválido",
  error_uri="https://…/docs/errors/invalid_token"
  • ·realm (opcional) — ámbito de protección; no debe repetirse.
  • ·scope (opcional) — lista de scopes requeridos separados por espacio, ej. "read write".
  • ·error (opcional) — razón del rechazo: invalid_request · invalid_token · insufficient_scope.
  • ·error_description (opcional) — explicación legible del error, solo para desarrolladores.
  • ·error_uri (opcional) — URI absoluta con documentación del error.
  • ·Si el token es un JWT, su header y payload son legibles (no cifrados) — no guardes secretos dentro.
Opción A · URL definida explícitamente (out-of-band)
# El cliente conoce el token endpoint de antemano (documentación, SDK, config)
→ POST https://auth.example.com/token
   grant_type=client_credentials&scope=read
← 200 { "access_token": "eyJ…", "token_type": "Bearer", "expires_in": 3600 }
Opción B · URL inferida vía RFC 8414 (issuer conocido)
# Si se conoce el issuer, se infiere la URL del AS metadata:
→ GET https://auth.example.com/.well-known/oauth-authorization-server
← 200 {
    "token_endpoint": "https://auth.example.com/token",
    "authorization_endpoint": "https://auth.example.com/authorize"
  }
# Fallback OIDC si 404:
→ GET https://auth.example.com/.well-known/openid-configuration
Respuesta del cliente
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…
  • ·RFC 6750 no incluye la URL del AS en el reto — el cliente debe conocerla de antemano o inferirla.
  • ·Opción A (definida): el token endpoint se configura explícitamente en el cliente (SDK, env var, docs).
  • ·Opción B (inferida): si se conoce el issuer, se construye /.well-known/oauth-authorization-server siguiendo RFC 8414.
  • ·Para discovery completamente automático desde el reto 401, usar Bearer + Discovery (RFC 9728).
Compatible con
  • Clientes API (curl, Postman, SDKs)
  • fetch / XMLHttpRequest
  • Clientes OAuth 2.0
Bearer + DiscoveryRFC 9728Moderno · Discovery

OAuth 2.0 Protected Resource Metadata. El reto 401 ya no solo dice "necesitas un Bearer": apunta a un documento de metadatos que describe DÓNDE y CÓMO obtener un token. El cliente descubre todo automáticamente.

Reto del servidor
WWW-Authenticate: Bearer resource_metadata="https://…/.well-known/oauth-protected-resource.json"
  • ·resource_metadata — único parámetro del reto; URL del documento de metadatos del recurso.
  • ·El cliente extrae authorization_servers[0] como issuer identifier del AS.
  • ·Habilita clientes genéricos: descubren el flujo completo a partir de un único 401.
  • ·Clave para ecosistemas como agentes y MCP, donde el cliente no conoce de antemano al emisor.
1 · Recurso retorna 401
← 401 WWW-Authenticate: Bearer resource_metadata="https://…/.well-known/oauth-protected-resource.json"
2 · Metadatos del recurso — RFC 9728
→ GET https://…/.well-known/oauth-protected-resource.json
← 200 {
    "resource": "https://…/demo/bearer2",
    "authorization_servers": ["https://auth.example.com"],
    "scopes_supported": ["read", "write"]
  }
3a · AS Metadata — RFC 8414
→ GET https://auth.example.com/.well-known/oauth-authorization-server
← 200 {
    "issuer": "https://auth.example.com",
    "authorization_endpoint": "https://auth.example.com/authorize",
    "token_endpoint": "https://auth.example.com/token",
    "scopes_supported": ["read", "write"],
    "grant_types_supported": ["authorization_code", "client_credentials"]
  }
3b · Fallback OpenID Connect Discovery
→ GET https://auth.example.com/.well-known/openid-configuration
← 200 {
    "issuer": "https://auth.example.com",
    "authorization_endpoint": "https://auth.example.com/authorize",
    "token_endpoint": "https://auth.example.com/token",
    "userinfo_endpoint": "https://auth.example.com/userinfo",
    "jwks_uri": "https://auth.example.com/jwks"
  }
4 · Obtener token y reintentar
→ POST https://auth.example.com/token
← 200 { "access_token": "eyJ…", "token_type": "Bearer", "expires_in": 3600 }

→ GET https://…/demo/bearer2
   Authorization: Bearer eyJ…
← 200 OK
  • ·Paso 3a — RFC 8414: busca /.well-known/oauth-authorization-server[/{path}] usando el issuer.
  • ·Paso 3b — Si 404, fallback a OpenID Connect Discovery: /.well-known/openid-configuration.
  • ·La construcción de la URL sigue la misma regla: well-known insertado entre host y path del issuer.
  • ·El documento AS expone authorization_endpoint, token_endpoint, scopes_supported, grant_types…
  • ·Con esos endpoints el cliente completa el flujo OAuth y obtiene un token Bearer válido.
Compatible con
  • Clientes MCP
  • Agentes de IA
  • Clientes OAuth 2.0 modernos (RFC 9728)

Glosario de términos

AS
Authorization Server — servidor que emite tokens de acceso tras verificar la identidad del cliente.
RS
Resource Server — servidor que aloja el recurso protegido y valida el token presentado.
Bearer
Esquema de token donde "quien lo porta, lo usa". El token debe protegerse como una credencial.
JWT
JSON Web Token — token firmado (y opcionalmente cifrado) cuyo header y payload son legibles en Base64.
Scope
Ámbito de acceso solicitado, ej. "read write". El AS puede otorgar un subconjunto de los scopes pedidos.
Nonce
Número usado una sola vez. En Digest previene ataques de repetición; en OIDC vincula el token al cliente.
Realm
Cadena que identifica el espacio de protección. Varias rutas del mismo servidor pueden compartir un realm.
Issuer
Identificador canónico del AS (URL). Se usa para derivar las URLs de discovery sin configuración previa.
OIDC
OpenID Connect — capa de identidad sobre OAuth 2.0 que añade un ID Token con datos del usuario.
MCP
Model Context Protocol — protocolo para agentes de IA que usa Bearer + Discovery (RFC 9728) para autenticarse.