Entrada

OAuth 2.0: el protocolo de delegación que redefinió la seguridad en APIs

Un recorrido por los orígenes de OAuth 2.0, las razones que lo convirtieron en el estándar de facto para la delegación de acceso en APIs, y los errores arquitectónicos más frecuentes al adoptarlo.

OAuth 2.0: el protocolo de delegación que redefinió la seguridad en APIs

Pocos protocolos han moldeado tanto la arquitectura de las aplicaciones modernas como OAuth 2.0. Su ubicuidad en APIs públicas, integraciones SaaS y plataformas móviles ha sido tal que resulta fácil olvidar qué problema vino a resolver y, sobre todo, qué problemas no resuelve. Este artículo forma parte de la serie La evolución de la seguridad en aplicaciones modernas, y revisita las decisiones de diseño que explican por qué seguimos usándolo, pese a sus aristas.

El problema que precede al estándar

A mediados de la década de 2000, la integración entre servicios web dependía de un patrón que hoy resulta escalofriante: entregarle tu contraseña de Gmail, Flickr o Twitter a una aplicación de terceros para que pudiera actuar en tu nombre. El password anti-pattern era la norma en agregadores de calendarios, clientes de escritorio y mashups de la Web 2.0. El usuario cedía credenciales primarias con alcance total, sin expiración, sin revocación granular y con la misma superficie de ataque que el servicio principal. Cambiar la contraseña era la única línea de defensa realista.

OAuth 1.0 (publicado en 2007 y formalizado como RFC 5849 en abril de 2010) fue la primera respuesta seria: introducía tokens de acceso limitados, firmados criptográficamente por el cliente con claves precompartidas y nonces para prevenir replay. El problema no era conceptual, sino operativo. Firmar cada petición con HMAC-SHA1 sobre un string canónico construido concatenando método, URL, parámetros ordenados y body era una fuente inagotable de errores: una coma de más en la codificación percent-encoded y toda la firma se invalidaba. Las librerías apenas coincidían. Los desarrolladores sufrían.

OAuth 2.0 (RFC 6749, octubre de 2012) tomó una decisión pragmática y polémica: delegar la seguridad del transporte a TLS y reemplazar las firmas por bearer tokens. La simplicidad ganó adopción; los puristas criticaron que el protocolo se convertía en “un framework, no un protocolo”. Eran dos lecturas correctas de lo mismo.

Los cuatro roles y por qué importan

OAuth 2.0 descompone el problema en cuatro actores que conviene tener grabados, porque casi todos los errores de diseño surgen de confundirlos.

El Resource Owner es la entidad (normalmente un usuario humano) que posee el recurso protegido y puede autorizar el acceso. El Client es la aplicación que quiere acceder a ese recurso en nombre del Resource Owner; puede ser una SPA, una app nativa, un backend server-to-server o un dispositivo IoT. El Authorization Server es quien autentica al Resource Owner, recoge su consentimiento y emite tokens. El Resource Server es la API que custodia el recurso y que valida los tokens para decidir si permite la operación.

La separación entre Authorization Server y Resource Server es el corazón arquitectónico del protocolo. Permite centralizar la emisión de credenciales y desacoplar la lógica de autorización de los servicios de negocio. En despliegues pequeños ambos roles pueden residir en el mismo proceso; en arquitecturas serias están separados, y esa separación es la que habilita patrones como federación, SSO entre dominios y rotación centralizada de claves.

Los grant types: flujos para contextos distintos

OAuth 2.0 no es un flujo único, sino una familia. Cada grant type optimiza un escenario específico.

Authorization Code

El flujo canónico para aplicaciones que pueden mediar un redireccionamiento del navegador. El cliente redirige al usuario al Authorization Server, el usuario se autentica y autoriza, el servidor responde con un code efímero por redirect, y el cliente canjea ese code por tokens en una llamada back-channel autenticada. La separación entre canal frontal (navegador) y canal trasero (servidor a servidor) es lo que da robustez al flujo: el access token nunca pasa por la URL.

Implicit

Diseñado originalmente para SPAs que no podían mantener un secreto. El Authorization Server devolvía el access token directamente en el fragmento de la URL de redirección. Rápido, pero expuesto: el token quedaba en el historial del navegador, en logs de referrer, accesible desde JavaScript y sin posibilidad de refresh. El Security Best Current Practice para OAuth 2.0 (RFC 9700, 2025) desaconseja explícitamente su uso. Hoy la recomendación es Authorization Code con PKCE también para SPAs.

Resource Owner Password Credentials

El cliente pide al usuario su contraseña y la envía al Authorization Server. Resuelve, sí, el mismo problema que OAuth vino a eliminar. Existe por retrocompatibilidad con flujos legacy o migraciones. Cualquier diseño nuevo que lo considere debería justificarlo por escrito.

Client Credentials

Autenticación máquina a máquina. No hay usuario implicado: el cliente se autentica con sus propias credenciales y recibe un token con scopes aplicables a su identidad. Es el flujo adecuado para comunicación entre microservicios o procesos batch.

Device Authorization Grant

Formalizado en RFC 8628 (agosto de 2019), resuelve el caso de dispositivos con capacidades limitadas de entrada: televisores, consolas, terminales de CLI. El dispositivo muestra un código y una URL; el usuario completa la autorización en otro dispositivo con navegador. Un patrón muy elegante para un problema real.

Access tokens, refresh tokens y el ciclo de vida

Un access token es una credencial efímera que el cliente presenta al Resource Server en cada petición, típicamente como Authorization: Bearer <token>. Su duración debe ser corta —minutos, no días— para limitar la ventana de abuso si se filtra. Cuando expira, el cliente usa un refresh token (credencial de larga duración, almacenada con cuidado) para obtener uno nuevo sin interacción del usuario.

El refresh token es un activo delicado. Debe rotarse en cada uso (refresh token rotation), invalidarse ante sospecha de reutilización y almacenarse exclusivamente en clientes confidenciales o bajo protección fuerte en el navegador (idealmente, en memoria). Filtrar un refresh token equivale a mantener acceso persistente a la cuenta del usuario.

Los scopes son la unidad de granularidad del consentimiento. read:profile, write:repo, admin:org son ejemplos que el Authorization Server presenta al usuario y graba en el token. Bien diseñados, permiten al usuario otorgar el mínimo privilegio necesario. Mal diseñados —un único scope full_access— reproducen el problema original que OAuth pretendía resolver.

OAuth 2.0 no es autenticación

Esta es, probablemente, la confusión más costosa del ecosistema. OAuth 2.0 es un protocolo de delegación de autorización. Un access token demuestra que alguien autorizó al cliente a hacer algo, no demuestra quién es ese alguien. Usar un access token como prueba de identidad —por ejemplo, confiar en que el sub devuelto por un endpoint /me es quien dice ser— abre la puerta a ataques de sustitución de tokens: un atacante obtiene un token válido de otra aplicación con el mismo Authorization Server y lo inyecta en tu login.

Para autenticación existe OpenID Connect, una capa construida sobre OAuth 2.0 que añade un ID Token con semántica de identidad y validaciones criptográficas específicas. Si tu diseño dice “autenticación con OAuth”, conviene revisarlo.

Un patrón que aparece con frecuencia: equipos que construyen su propio “OIDC casero” decodificando el access token para extraer el email. Si el token no fue emitido para tu audiencia, estás construyendo el confused deputy de manual.

Riesgos clásicos y defensas

Los bearer tokens son cómodos y peligrosos por la misma razón: poseerlos equivale a usarlos. Tres vectores merecen atención permanente.

El robo de tokens en tránsito o reposo es la amenaza base. TLS con versiones modernas y pinning donde aplique, almacenamiento en memoria para SPAs, httpOnly y Secure para cookies de sesión cuando se use ese patrón, y rotación agresiva limitan el daño. Técnicas como sender-constrained tokens (mTLS-bound, RFC 8705, o DPoP, RFC 9449) añaden vinculación criptográfica al cliente: tener el token ya no basta.

El ataque CSRF sobre el redirect se mitiga con el parámetro state: un valor opaco, criptográficamente aleatorio, que el cliente genera antes de iniciar el flujo y verifica al recibir el callback. Omitirlo es un error tan frecuente como perjudicial.

El problema del confused deputy aparece cuando un Authorization Server emite tokens con scopes amplios que un cliente intermedio usa para operar sobre recursos del usuario sin intención clara por parte de este. Scopes finos, audiencias explícitas (aud) y consentimiento granular son los antídotos.

Cuándo adoptarlo y cuándo no

OAuth 2.0 es la elección natural cuando hay terceros involucrados: aplicaciones externas accediendo a tu API, SSO entre dominios distintos, integraciones B2B o despliegues multi-tenant con separación estricta. También cuando la arquitectura tiene múltiples consumidores (web, móvil, CLI, máquina a máquina) y quieres un plano de autorización unificado.

No es la respuesta cuando el problema se reduce a autenticar usuarios en tu propia aplicación monolítica, con un único cliente y un único servidor bajo tu control. Una sesión basada en cookie bien configurada resuelve ese caso con menos piezas móviles y menos superficie de ataque. Introducir un Authorization Server para emitir tokens a tu propio frontend añade complejidad sin ganancia clara.

Tampoco resuelve autorización fina a nivel de recurso (ver RBAC, ABAC y ReBAC): los scopes son un filtro grueso, no un motor de políticas. La decisión “este usuario puede editar este documento concreto” pertenece al Resource Server, apoyado en un sistema de políticas.

Adoptar OAuth 2.0 sin un IdP maduro detrás es uno de los errores recurrentes. Implementar un Authorization Server propio desde cero es un proyecto serio; delegar en Keycloak, Okta u otros IdPs casi siempre es la decisión correcta.

Artículos relacionados en esta serie

Referencias

  • RFC 5849 (abril 2010). The OAuth 1.0 Protocol.
  • RFC 6749 (octubre 2012). The OAuth 2.0 Authorization Framework.
  • RFC 6750 (octubre 2012). The OAuth 2.0 Authorization Framework: Bearer Token Usage.
  • RFC 8628 (agosto 2019). OAuth 2.0 Device Authorization Grant.
  • RFC 8705 (febrero 2020). OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens.
  • RFC 9449 (septiembre 2023). OAuth 2.0 Demonstrating Proof of Possession (DPoP).
  • RFC 9700 (2025). Best Current Practice for OAuth 2.0 Security.
  • IETF OAuth Working Group. OAuth 2.1 Draft.
Esta entrada está licenciada bajo CC BY 4.0 por el autor.