main content
< Volver a blog sobre aplicaciones móviles

Diseño autenticación OAuth2 y JWT para app web

Cómo diseñar un sistema de autenticación OAuth2 y JWT para tu aplicación web a medida

El 31 % de las brechas de seguridad registradas en la última década han involucrado credenciales robadas o comprometidas. Así lo recoge el Data Breach Investigations Report 2024 de Verizon. Para quienes desarrollan software a medida, esta cifra no es un titular anecdótico: es el recordatorio de que la autenticación no es un módulo que se añade al final del proyecto, sino una decisión arquitectónica que condiciona la escalabilidad, la experiencia de usuario y la postura de seguridad del producto durante toda su vida útil.

OAuth2 y JWT se han convertido en el estándar de facto para resolver este problema. Lo que sigue es una guía técnica sobre cómo estructurar un sistema de autenticación con OAuth2 y JWT en una aplicación web personalizada: desde la selección del flujo correcto hasta las estrategias de refresco de tokens y las vulnerabilidades que conviene anticipar antes de que aparezcan.

Fundamentos de OAuth2: qué problema resuelve y cómo

OAuth2 es un framework de autorización delegada definido en la RFC 6749. Su propósito original no era autenticar usuarios, sino permitir que una aplicación tercera acceda a recursos protegidos en nombre del usuario sin compartir sus credenciales. Con el tiempo, combinado con OpenID Connect (OIDC), ha extendido su alcance para cubrir también la autenticación.

Los cuatro roles del protocolo

El modelo define cuatro actores: el resource owner (normalmente el usuario), el client (la aplicación que solicita acceso), el authorization server (quien emite tokens) y el resource server (la API que protege los datos). Entender esta separación antes de escribir una sola línea de código no es opcional. Determina dónde reside cada responsabilidad y qué puede salir mal si se mezclan.

Flujos OAuth2 y cuándo usar cada uno

No todos los flujos sirven para todos los escenarios. Elegir el incorrecto introduce riesgos que ningún parche posterior corrige del todo.

Authorization Code con PKCE es el flujo recomendado para aplicaciones web modernas, tanto con backend como SPA. PKCE (Proof Key for Code Exchange) mitiga ataques de interceptación del código de autorización. La OAuth 2.1 draft specification lo exige desde 2023 para todos los clientes, incluidos los confidenciales.

Client Credentials cubre la comunicación máquina a máquina (M2M), donde no interviene ningún usuario. Habitual en microservicios que consumen APIs internas.

Device Authorization Grant está pensado para dispositivos con entrada limitada, como smart TVs o IoT. Raramente aplica en desarrollo web convencional, aunque vale conocerlo en arquitecturas híbridas.

Implicit Flow está obsoleto. La especificación OAuth 2.1 lo elimina formalmente. Si tu aplicación aún lo utiliza, migrar a Authorization Code con PKCE debería ser la prioridad inmediata.

Estructura y validación de JSON Web Tokens

JWT (RFC 7519) es un formato compacto y autocontenido para transmitir claims entre partes. Tres segmentos codificados en Base64URL, separados por puntos: header, payload y signature. La estructura es simple; los errores de implementación, no tanto.

Header

Contiene el algoritmo de firma —RS256 o ES256 son las opciones recomendadas— y el tipo de token. Evita algoritmos simétricos como HS256 en entornos donde múltiples servicios necesiten verificar el token: compartir la clave secreta amplía la superficie de ataque de forma innecesaria.

Payload (claims)

Incluye claims registrados (iss, sub, aud, exp, iat, nbf, jti) y claims personalizados. Dos errores que se repiten con frecuencia: almacenar datos sensibles en el payload —es legible por cualquiera que posea el token— e ignorar el claim aud, lo que abre la puerta a ataques de confusión de audiencia entre servicios.

Firma y validación

La firma garantiza integridad, pero solo si la validación es rigurosa. Al verificar un JWT, tu aplicación debe comprobar que la firma corresponde al algoritmo declarado en el header, que el token no ha expirado (claim exp), que el emisor (iss) y la audiencia (aud) coinciden con los valores esperados, y que el token no se emitió en el futuro (claims iat/nbf).

Omitir cualquiera de estos pasos ha provocado vulnerabilidades documentadas en CVE recurrentes. La biblioteca jose en Node.js y PyJWT en Python cubren estos controles, pero requieren configuración explícita para rechazar algoritmos inesperados —el llamado ataque de confusión de algoritmo, ilustrado por CVE-2022-21449 en Java.

Estrategias de refresh token

Un access token JWT con vida corta —entre 5 y 15 minutos es lo habitual— limita el daño si resulta comprometido. Pero la experiencia de usuario exige sesiones persistentes sin forzar un nuevo login constantemente. Ahí entran los refresh tokens.

Rotación de refresh tokens

Cada vez que el cliente usa un refresh token para obtener un nuevo access token, el authorization server emite también un refresh token nuevo e invalida el anterior. Si un atacante intercepta uno y lo usa, el servidor detecta la reutilización del token ya rotado y revoca toda la cadena. Esta técnica, recomendada por la IETF en la RFC 6749 Section 10.4 y ampliada en el BCP OAuth 2.0 Security, reduce drásticamente la ventana de explotación.

Almacenamiento seguro

En aplicaciones web con backend, los refresh tokens deben vivir en cookies HttpOnly, Secure y SameSite=Strict. Nunca en localStorage ni en sessionStorage, donde cualquier script XSS puede leerlos. Un estudio de la Universidad de Darmstadt de 2023 constató que el 43 % de las SPAs analizadas almacenaban tokens en almacenamiento accesible por JavaScript. El dato habla por sí solo.

Gestión de sesiones en aplicaciones web modernas

El diseño del sistema de autenticación debe contemplar cómo se relacionan los tokens con las sesiones. No basta con emitir tokens correctamente; hay que pensar en qué ocurre cuando caducan, cuando el usuario cierra sesión o cuando hay una brecha.

Patrón BFF (Backend For Frontend)

Cuando el frontend es una SPA y existe un backend propio, el patrón BFF gestiona los tokens en el servidor. El navegador solo recibe una cookie de sesión opaca; los access tokens nunca llegan al cliente JavaScript. El resultado es un frontend con menor superficie de ataque y la posibilidad de revocar sesiones de forma centralizada, sin depender de la expiración natural del token.

Sesiones sin estado vs. con estado

Un JWT es inherentemente sin estado: el servidor no consulta ninguna base de datos para validarlo. Eso lo hace eficiente, pero complica la revocación inmediata —por ejemplo, cuando un usuario cambia su contraseña. Las soluciones habituales pasan por listas de revocación (JTI blacklist) almacenadas en Redis con TTL igual al tiempo de expiración del token, o por combinar JWT de corta vida con refresh tokens revocables en base de datos.

Si tu equipo está evaluando cómo estructurar la autenticación de un proyecto nuevo, o necesita auditar un sistema existente, en Tangram Consulting podemos ayudarte a tomar las decisiones arquitectónicas adecuadas desde las fases iniciales del diseño.

Integración con proveedores de identidad

Delegar la autenticación a un Identity Provider (IdP) externo elimina la carga de mantener un sistema propio de gestión de credenciales. Google, Microsoft Entra ID (antes Azure AD) y Auth0 son los más usados en el mercado español.

Protocolo OpenID Connect

OIDC es una capa de identidad construida sobre OAuth2. Añade el ID token —un JWT con información del usuario— y endpoints estandarizados como userinfo y discovery. Al integrar un IdP, valida el ID token con el mismo rigor que cualquier otro JWT y verifica el nonce para prevenir ataques de replay. La delegación no exime de la validación.

Federación y multitenant

En aplicaciones B2B es frecuente que cada cliente corporativo traiga su propio IdP, sea SAML u OIDC. Diseñar el sistema para soportar múltiples emisores desde el principio evita reescrituras costosas más adelante. Keycloak y Ory Hydra son soluciones open source que facilitan la federación en despliegues on-premise.

Buenas prácticas de seguridad

El protocolo correcto no garantiza una implementación segura. La superficie de ataque surge en los detalles concretos.

Prevención de vulnerabilidades comunes

CSRF: el parámetro state en el flujo OAuth2 debe ser un valor aleatorio vinculado a la sesión del usuario y verificado en la respuesta del authorization server.

Open Redirect: valida que el redirect_uri coincide exactamente con la URL registrada. Nada de coincidencias parciales ni comodines.

Token leakage en logs: los tokens no deben aparecer en URLs, logs de servidor ni herramientas de monitorización. Usa headers Authorization con esquema Bearer.

Escalada de privilegios: implementa scopes granulares y valídalos en cada endpoint del resource server, no solo en el gateway.

Cabeceras HTTP de seguridad

Complementa la autenticación con cabeceras como Content-Security-Policy (para mitigar XSS), Strict-Transport-Security (para forzar HTTPS) y X-Content-Type-Options. No sustituyen una buena implementación OAuth2, pero forman parte del perímetro defensivo que cualquier aplicación web debería tener.

Monitorización y respuesta ante incidentes

Un sistema de autenticación sin observabilidad es un sistema ciego. Registra los eventos relevantes: intentos de login fallidos, emisión y uso de refresh tokens, cambios de contraseña, revocaciones de sesión y errores de validación de JWT. Sobre esos datos, establece alertas para patrones anómalos —un número inusual de rotaciones de refresh token desde una misma cuenta puede indicar un ataque de repetición; peticiones con tokens expirados desde IPs no habituales merecen atención inmediata.

Herramientas como el stack ELK, Datadog o Grafana Loki permiten centralizar estos logs y correlacionarlos con métricas de la aplicación. El informe Cost of a Data Breach 2024 de IBM es directo al respecto: las organizaciones con capacidades avanzadas de detección reducen el coste medio de una brecha en un 28 %. La observabilidad desde la fase de diseño no es un lujo; es lo que separa un incidente gestionado de uno que escala.

Testing del flujo de autenticación

La autenticación exige pruebas específicas que van más allá de los tests unitarios convencionales.

Tests de integración con el IdP: usa entornos sandbox de los proveedores —Google ofrece test users, Auth0 tiene tenants de desarrollo— para verificar el flujo completo sin depender de credenciales reales.

Tests de seguridad automatizados: herramientas como OWASP ZAP o Burp Suite se integran en el pipeline CI/CD para detectar vulnerabilidades como open redirect o inyección en parámetros OAuth antes de que lleguen a producción.

Tests de expiración y rotación: simula escenarios donde el access token expira durante una operación en curso y verifica que el cliente renueva el token de forma transparente sin perder la petición original.

Tests de revocación: comprueba que al revocar un refresh token, todos los access tokens derivados dejan de ser válidos dentro del margen aceptable, según uses blacklist o esperes a la expiración natural.

Un sistema de autenticación OAuth2 con JWT bien diseñado no se construye en una tarde. Las decisiones que se toman en las primeras semanas del proyecto —qué flujo usar, cómo almacenar los tokens, cómo revocar sesiones— determinan la seguridad y la mantenibilidad del producto durante años. Anticipar las amenazas conocidas es, técnicamente, la inversión con mayor retorno que puedes hacer en una aplicación web a medida.

Contacta con nosotros
Fila 1