JWT Actualizar rotación de token: patrón seguro para sistemas reales

La mayoría de los tutoriales de JWT se detienen en "usar un token de actualización para sesiones de larga duración". Rara vez explican qué sucede cuando se roba ese token de actualización. Un token de actualización estático (uno que nunca cambia) le da al atacante el mismo acceso persistente que una cookie de sesión robada. Peor aún, no hay forma de detectar el robo.
Rotación de token de actualización resuelve este problema emitiendo un nuevo token de actualización con cada uso. Si se reproduce un token antiguo, se revoca toda la sesión. Este artículo explica el patrón de implementación utilizado por Auth0, Okta y otros proveedores de identidad serios.
Por qué fallan los tokens de actualización estática
Un token de actualización estático tiene un valor fijo durante toda la vida útil de la sesión (a menudo, más de 30 días). Problemas:
- El robo es silencioso: si un atacante roba el token de actualización, puede generar nuevos tokens de acceso indefinidamente sin que el usuario lo sepa
- Sin detección de repetición — el mismo token se puede usar repetidamente desde diferentes ubicaciones
- La revocación es burda — para invalidar un token robado, a menudo es necesario invalidar todas las sesiones de usuario
La solución es tratar cada token de actualización como de un solo uso.
El modelo de rotación
Paso 1: Iniciar sesión: crear una familia de tokens
Cuando el usuario se autentica, genera un family_id (UUID) que agrupa todos los tokens en esta sesión:
{ family_id: "f47ac10b-58cc-4372-a567-0e02b2c3d479", user_id: "user_123", refresh_token_hash: sha256(refresh_token), created_at: "2026-03-28T10:00:00Z", expires_at: "2026-04-27T10:00:00Z", used: false
}Almacena este registro en el lado del servidor. Nunca almacene tokens de actualización en localStorage: utilice cookies httpOnly o almacenamiento nativo seguro.
Paso 2: Actualización del token: rotar
Cuando el cliente presenta el token de actualización:
- Busca el hash del token en la base de datos
- Verifique que pertenece a una familia activa y que no está marcado como
usado - Marcarlo como
usado: verdadero - Emitir un nuevo token de actualización (nuevo valor aleatorio, mismo
family_id) - Emitir un nuevo token de acceso
- Almacena el nuevo hash del token de actualización
Paso 3: Detección de repetición
Si se presenta nuevamente un token de actualización marcado como usado: true, esto significa:
- Un atacante está reproduciendo un token robado, o
- Un cliente legítimo está reintentando después de una falla en la red
La respuesta segura: revocar todos los tokens de la familia. Esto obliga al usuario a iniciar sesión nuevamente. Es mejor causarle molestias a un usuario legítimo una vez que permitir que un atacante mantenga el acceso.
// Repetición detectada: opción nuclear
esperar db.query ( 'ELIMINAR DE refresco_tokens DONDE family_id = $1', [ID de familia]
);Esquema de base de datos
Una tabla de tokens de actualización mínima:
CREAR TABLA refresco_tokens ( id UUID CLAVE PRIMARIA POR DEFECTO gen_random_uuid(), family_id UUID NO NULO, user_id UUID NO REFERENCIAS NULAS usuarios(id), token_hash TEXTO NO NULO ÚNICO, usado BOOLEANO POR DEFECTO FALSO, creado_en TIMESTAMPTZ DEFAULT ahora(), expires_at TIMESTAMPTZ NO NULO, reemplazado_por REFERENCIAS UUID actualizar_tokens(id)
); CREAR ÍNDICE idx_refresh_family EN refresco_tokens(family_id);
CREAR ÍNDICE idx_refresh_user EN actualizar_tokens(user_id);La columna replaced_by crea una cadena que puede seguir con fines de auditoría.
Manejo de solicitudes simultáneas
En aplicaciones reales, varias llamadas API pueden activar una actualización simultáneamente. Si la Llamada A rota el token mientras la Llamada B todavía retiene el antiguo, la Llamada B activa la detección de repetición, lo que cierra la sesión del usuario inesperadamente.
Patrón de período de gracia
Permitir que el token de actualización anterior siga siendo válido durante un período breve (de 5 a 10 segundos) después de la rotación:
const GRACE_PERIOD_MS = 10_000; si (token.usado) { const transcurrido = Fecha.ahora() - token.rotated_at; si (transcurrido < GRACE_PERIOD_MS) { // Within grace period — return the already-issued new tokens return getLatestTokensForFamily(token.family_id); } // Outside grace period — replay attack await revokeFamily(token.family_id); throw new UnauthorizedError('token_replayed');
}Monitoreo y Alertas
Seguimiento de estas señales en producción:
- Reproducir eventos por hora: un pico indica un ataque activo o un error del lado del cliente
- Revocaciones familiares: tasas altas pueden indicar robo de tokens o un cliente mal configurado
- Frecuencia de actualización por usuario: tasas anormalmente altas sugieren recolección de tokens
- Anomalías geográficas: actualización desde un país diferente al inicio de sesión original
Token de actualización frente a token de acceso: referencia rápida
| Propiedad | Token de acceso | Token de actualización |
|---|---|---|
| Vida útil | 5–15 minutos | 7–30 días |
| Formato | JWT (autónomo) | Cadena opaca (recomendado) |
| Almacenamiento | Memoria (variable JS) | httpOnly cookie |
| Enviado a | Servidores API | Solo servidor de autenticación |
| Rotación | No es necesario | Cada uso |
Para errores de validación de reclamación de tiempo que a menudo interactúan con los flujos de actualización, consulte JWT exp/iat/nbf errores comunes.
Preguntas frecuentes
¿Cómo debo manejar las solicitudes de actualización simultáneas?
Utilice un período de gracia breve (de 5 a 10 segundos) en el que aún se acepte el token de actualización anterior. Esto maneja las condiciones de carrera cuando varias llamadas API activan una actualización simultáneamente. Después del período de gracia, solo es válido el token más nuevo.
¿Los tokens de actualización deben ser JWT o cadenas opacas?
Las cadenas opacas generalmente son más seguras para los tokens de actualización. Los JWT transportan datos de carga útil que aumentan la superficie de ataque y los tokens de actualización no necesitan ser autónomos, ya que el servidor siempre los busca en la base de datos de todos modos.
¿Cuánto tiempo deben durar las sesiones de actualización?
Lo típico es7–30 días. Las aplicaciones de alta seguridad (banca, atención médica) deberían tardar entre 1 y 7 días. Las aplicaciones para consumidores pueden durar hasta 90 días con rotación. Empareje siempre sesiones largas con huellas dactilares del dispositivo y detección de anomalías.
Herramientas y artículos relacionados
- JWT Decoder — inspeccionar tokens y verificar reclamos de tiempo
- Errores de seguridad de JWT: errores comunes de JWT más allá de los tokens de actualización
- Errores de reclamación de tiempo de JWT: desfase del reloj y problemas de orden de validación
- 2FA Guía — fortalecer la autenticación más allá de los tokens