OpenID Connect · OAuth 2.0
Estos mecanismos refuerzan la seguridad del flujo base. Cada uno responde a una debilidad concreta: partimos del problema y luego la solución.
El hilo conductor
El flujo base envía información a través del navegador, donde cualquiera puede manipularla. Las funciones avanzadas lo corrigen en cada paso: PAR y JAR protegen la solicitud, private_key_jwt protege la identidad de la aplicación, JARM protege la respuesta, DPoP protege el token una vez emitido y CIBA gestiona el caso en que no hay navegador. A ello se suman resource (qué API), RAR (qué operación precisa), acr (qué nivel de autenticación) y el registro dinámico de clientes.
private_key_jwt · PAR · JAR · JARM · DPoP · CIBA · Resource indicators · RAR · acr y step-up · Registro dinámico de clientes · Pairwise y userinfo firmado
RFC 7523 / OIDC Core 9
Pruebe quién es con una firma en lugar de una contraseña compartida.
Un cliente confidencial se autentica normalmente con un «client_secret», una contraseña que conocen el cliente y el servidor. Si se filtra en un lado, el otro no tiene forma de saberlo, y el secreto viaja por archivos de configuración.
El cliente conserva una clave privada que nunca sale de sus instalaciones. En cada llamada construye una pequeña «atestación» firmada (un JWT) que dice «soy este cliente, me dirijo a este servidor y esto solo es válido unos minutos». El servidor solo tiene la clave pública: verifica la firma, y nada más.
Como imagen
En lugar de una contraseña que conoce el guardia, firma cada entrada con su pluma personal; el guardia solo tiene un espécimen de su firma.
Bancos, administraciones públicas, cualquier entorno que prohíba los secretos compartidos. Obligatorio en varios perfiles de seguridad (FAPI).
Aserción reutilizada (de ahí el identificador «jti» de un solo uso), audiencia incorrecta, duración demasiado larga, clave errónea.
Cree un cliente «Confidencial con clave (private_key_jwt)» en su proveedor de pruebas, pegue su certificado o JWKS público y luego llame a /token con client_assertion. ID-Kit le dice con precisión por qué se rechaza una aserción.
RFC 9126
Enviar su solicitud de inicio de sesión directamente al servidor, sin pasar por el navegador.
Normalmente, la solicitud (quién soy, qué quiero, adónde volver) se escribe en la dirección de la página y viaja por el navegador: el usuario o un software malicioso pueden leerla o cambiarla, y las direcciones muy largas son un problema.
La aplicación envía primero toda su solicitud al servidor, de servidor a servidor, autenticándose. El servidor responde con un simple «ticket» (request_uri) válido un minuto. La aplicación envía entonces el navegador al servidor solo con ese ticket. El ticket solo puede usarse una vez.
Como imagen
En lugar de gritar su pedido por el comedor, se lo entrega a la cocina y solo muestra a la sala un número de ticket.
Siempre que quiera impedir que se manipule un parámetro (importe, scopes, redirect_uri): banca, sanidad, pagos. Exigido por FAPI.
Ticket caducado (60 s), ya utilizado o presentado por un cliente distinto del que lo envió.
Proveedor de pruebas: llame a /par. En la aplicación de pruebas, elija el flujo «code_par». El ajuste «Require PAR» del proveedor rechaza las solicitudes clásicas.
RFC 9101
Firmar la solicitud de inicio de sesión para que nadie pueda modificarla por el camino.
Aun con los parámetros en la dirección, nada prueba que procedan realmente de la aplicación y no se hayan cambiado.
Los parámetros se reúnen en un JWT firmado con la clave del cliente (parámetro «request»). El servidor verifica la firma, el emisor, la audiencia y la fecha. Los parámetros del JWT sustituyen a los de la dirección.
Como imagen
Una carta en un sobre sellado con lacre: si el sello está roto, el servidor lo ve.
Con PAR en perfiles de alta seguridad; solo, cuando no hay canal de servidor a servidor.
Clave pública del cliente no registrada, «aud» que no es el emisor del servidor, JWT caducado, client_id distinto.
Registre la clave pública del cliente y envíe su JWT en «request» o a /par. Se explican las firmas y audiencias incorrectas.
FAPI JARM
El servidor también firma su respuesta: la aplicación sabe que procede realmente de él y que no se ha modificado.
Cuando el servidor devuelve al usuario a la aplicación con «code=…» en la dirección, cualquiera en el navegador puede tocarlo. Esto abre la puerta a ataques en los que otro servidor suplanta al correcto («mix-up»).
En lugar de varios parámetros simples, el servidor devuelve un único parámetro «response»: un JWT firmado que contiene code, state, el emisor (iss) y la audiencia (aud). La aplicación verifica la firma y luego lee el código que contiene. Cuatro variantes: jwt, query.jwt, fragment.jwt, form_post.jwt (según dónde se coloque el JWT).
Como imagen
La respuesta llega en un sobre sellado en lugar de en una postal.
Perfil FAPI 2.0 y sectores regulados. También útil para detectar ataques mix-up entre servidores.
Olvidar verificar la firma, o leer parámetros simples junto al JWT. query.jwt está prohibido cuando los tokens vuelven por el navegador.
Añada response_mode=jwt (o una variante) a su solicitud de autorización en el proveedor de pruebas: incluso una denegación o un error van firmados.
RFC 9449
Un token robado es inútil sin la clave de la aplicación que lo solicitó.
Un token «Bearer» funciona como el dinero en efectivo: quien lo tiene puede usarlo, aunque lo haya robado de un registro, una extensión del navegador o una API comprometida.
La aplicación crea un par de claves. En cada llamada adjunta una breve «prueba» firmada con su clave privada que dice «este es el método y la dirección a la que llamo, en este instante». El servidor vincula el token a la huella de la clave (cnf.jkt). La API comprueba que la prueba fue firmada por la misma clave y que lleva el hash del token (ath). Un ladrón que tenga el token pero no la clave privada queda bloqueado.
Como imagen
Una tarjeta bancaria con PIN, en lugar de billetes: la tarjeta sola no basta.
Aplicaciones móviles y páginas web (SPA) donde los tokens quedan expuestos, API sensibles, perfiles FAPI 2.0.
Prueba reutilizada (jti de un solo uso), método o dirección incorrectos (htm, htu), reloj desfasado (iat ±2 min), token presentado con «Bearer» en lugar de «DPoP», ath ausente en la API.
Envíe una cabecera DPoP al /token del proveedor de pruebas: el token pasa a ser token_type DPoP con cnf.jkt. En /userinfo, se necesita «Authorization: DPoP» más una prueba con ath; si no, un mensaje explica lo que falta.
OpenID CIBA Core
Una aplicación pide al servidor que autentique a alguien en su teléfono, sin navegador ni redirección.
En una ventanilla, un centro de llamadas, un terminal de pago o un asistente de voz, la persona no está frente a un navegador que pueda redirigir.
La aplicación dice al servidor «autentica a Alice» (login_hint), opcionalmente con un mensaje que mostrar («¿Autoriza el pago de 25 €?») y recibe un auth_req_id. El servidor contacta con Alice en su teléfono. Mientras tanto, la aplicación consulta /token: «authorization_pending» mientras Alice no haya respondido; después los tokens si acepta, o «access_denied» si rechaza.
Como imagen
El vendedor llama a su banco para decir «mi cliente está aquí», y es su banco quien le envía una notificación para confirmar.
Validación de pagos u operaciones sensibles, centros de llamadas, quioscos, telefonía. El mensaje de vinculación (binding_message) aparece en ambas pantallas para comprobar que se valida la operación correcta.
Consultar demasiado rápido (slow_down), dejar caducar la solicitud, olvidar que login_hint debe designar a un usuario conocido por el servidor.
Active el flujo CIBA en un cliente del proveedor de pruebas y llame a /bc-authorize. La respuesta contiene un enlace «idkit_approval_url»: es la página del «teléfono», donde aprueba o deniega; después obtiene los tokens con /token. ID-Kit solo admite el modo poll.
RFC 8707
Diga con qué API quiere hablar, para que el token solo funcione allí.
Un access token válido para «cualquier API» es peligroso: si la API de facturación se ve comprometida, puede reutilizar el token contra la API de nóminas.
La aplicación añade «resource=https://api.example.com/invoices» a su solicitud (de autorización o de token). El proveedor pone esta dirección en la audiencia (aud) del token. La API comprueba que aud es ella misma y, si no, rechaza.
Como imagen
Un billete de tren nominativo para una línea concreta, en lugar de un billete válido en todas partes.
En cuanto haya varias API detrás del mismo proveedor, y para los tokens sensibles.
API que no comprueba aud; recurso con fragmento (#) o que no es una dirección absoluta (invalid_target).
Añada resource a /authorize o /token del proveedor de pruebas: cambia la audiencia del token JWT y de la introspección. El recurso se recuerda en el código y se conserva en el refresh.
RFC 9396
Pida un derecho preciso («pagar 25 € a X») en lugar de un scope amplio («pagar»).
Un scope como «payments» es demasiado vago: el usuario no sabe lo que aprueba y el token permite mucho más que la operación prevista.
La aplicación envía authorization_details: una lista JSON de objetos con un «type» (por ejemplo payment_initiation) y los detalles de la operación (importe, beneficiario). El proveedor los muestra, los copia en el token y en la respuesta, y la API los lee.
Como imagen
Un cheque rellenado (importe, beneficiario) en lugar de un cheque en blanco.
Pagos, sanidad, delegación fina. Obligatorio en algunos perfiles bancarios.
JSON no válido o falta «type» (invalid_authorization_details); API que ignora el contenido del token.
Envíe authorization_details a /authorize o /token: ID-Kit lo valida y lo vuelve a encontrar en el token, en la respuesta de /token y en la introspección.
OIDC Core, RFC 9470
Saber con qué fuerza se autenticó la persona y exigir más si hace falta.
Iniciar sesión con una contraseña no basta para transferir 10 000 €. La aplicación debe poder decir «quiero autenticación fuerte».
La aplicación pide acr_values (por ejemplo el nivel «mfa»). El proveedor devuelve en el ID token el valor acr obtenido y la lista amr de métodos usados (contraseña, código de un solo uso…). Una API puede rechazar un token de nivel demasiado bajo y pedir un «step-up»: la persona vuelve a autenticarse con más fuerza.
Como imagen
En el banco, puede consultar su cuenta con la tarjeta, pero para una transferencia grande le piden además un documento de identidad.
Operaciones sensibles, cumplimiento normativo (autenticación fuerte).
Tratar acr_values como una exigencia cuando es una petición («voluntaria»); no comprobar el acr recibido.
Añada acr_values=urn:idkit:acr:mfa: el ID token contiene acr y amr [pwd, otp], y la introspección devuelve acr y auth_time. Sin solicitud, el nivel es «pwd».
RFC 7591
Una aplicación se registra por sí misma en el proveedor, sin pasar por un administrador.
Crear clientes a mano no escala: herramientas, extensiones, servidores MCP, aplicaciones móviles instaladas por miles de personas.
La aplicación envía un POST JSON a /register (nombre, direcciones de retorno, flujos deseados, método de autenticación). El proveedor crea el cliente y devuelve client_id y, si procede, client_secret.
Como imagen
Un quiosco de inscripción de autoservicio en lugar de una cita en recepción.
Ecosistemas abiertos, herramientas que se conectan a proveedores desconocidos.
Redirecciones inseguras (http fuera de localhost), grants incoherentes con el método de autenticación, sin límite.
Active «Allow dynamic registration» en los ajustes del proveedor de pruebas y luego haga POST a /register. El límite es de 25 clientes.
OIDC Core 8.1 y 5.3.2
Un identificador distinto por aplicación e información de perfil firmada.
Si todas las aplicaciones ven el mismo identificador (sub) de una persona, pueden cruzar sus bases de datos y seguirla de un servicio a otro.
En modo pairwise, el proveedor calcula un sub distinto para cada dominio de aplicación: el mismo usuario aparece con dos identificadores diferentes en dos aplicaciones. Por separado, /userinfo puede responder con un JWT firmado en lugar de JSON simple, para que la aplicación pueda probar de dónde proceden los datos.
Como imagen
Un seudónimo distinto por sitio en lugar de un número de la seguridad social en todas partes.
Privacidad (administraciones públicas, sanidad, educación); entornos donde la información de perfil debe ir firmada.
Vincular cuentas entre aplicaciones con sub (imposible con pairwise); olvidar que el sub de userinfo debe ser idéntico al del ID token.
Dos ajustes en el proveedor de pruebas: «Identificador por aplicación (pairwise)» y «userinfo como JWT firmado».
Vea también: diagramas de secuencia · ¿qué flujo elegir? · la línea de tiempo