online jsonwebtoken decoded create node.js api security authentication jwt

node.js - jsonwebtoken - JWT(JSON Web Token) prolongación automática de la caducidad



jwt php (9)

jwt-autorefresh

Si está utilizando el nodo (React / Redux / Universal JS) puede instalar npm i -S jwt-autorefresh .

Esta biblioteca programa la actualización de tokens JWT en un número de segundos calculado por el usuario antes de que el token de acceso caduque (según la reclamación exp codificada en el token). Cuenta con un extenso conjunto de pruebas y verifica varias condiciones para garantizar que cualquier actividad extraña esté acompañada por un mensaje descriptivo sobre las configuraciones erróneas de su entorno.

Ejemplo completo de implementación

import autorefresh from ''jwt-autorefresh'' /** Events in your app that are triggered when your user becomes authorized or deauthorized. */ import { onAuthorize, onDeauthorize } from ''./events'' /** Your refresh token mechanism, returning a promise that resolves to the new access tokenFunction (library does not care about your method of persisting tokens) */ const refresh = () => { const init = { method: ''POST'' , headers: { ''Content-Type'': `application/x-www-form-urlencoded` } , body: `refresh_token=${localStorage.refresh_token}&grant_type=refresh_token` } return fetch(''/oauth/token'', init) .then(res => res.json()) .then(({ token_type, access_token, expires_in, refresh_token }) => { localStorage.access_token = access_token localStorage.refresh_token = refresh_token return access_token }) } /** You supply a leadSeconds number or function that generates a number of seconds that the refresh should occur prior to the access token expiring */ const leadSeconds = () => { /** Generate random additional seconds (up to 30 in this case) to append to the lead time to ensure multiple clients dont schedule simultaneous refresh */ const jitter = Math.floor(Math.random() * 30) /** Schedule autorefresh to occur 60 to 90 seconds prior to token expiration */ return 60 + jitter } let start = autorefresh({ refresh, leadSeconds }) let cancel = () => {} onAuthorize(access_token => { cancel() cancel = start(access_token) }) onDeauthorize(() => cancel())

descargo de responsabilidad: yo soy el mantenedor

Me gustaría implementar la autenticación basada en JWT para nuestra nueva API REST. Pero dado que la caducidad se establece en el token, ¿es posible prolongarlo automáticamente? No quiero que los usuarios tengan que iniciar sesión después de cada X minutos si utilizaron activamente la aplicación en ese período. Eso sería un gran error de UX.

Pero prolongar la caducidad crea un nuevo token (y el anterior sigue siendo válido hasta que caduque). Y generar una nueva ficha después de cada solicitud me parece una tontería. Suena como un problema de seguridad cuando más de un token es válido al mismo tiempo. Por supuesto, podría invalidar el antiguo usado utilizando una lista negra, pero necesitaría almacenar los tokens. Y uno de los beneficios de JWT es el almacenamiento.

Encontré cómo lo resolvió Auth0. Utilizan no solo el token JWT sino también un token de actualización: https://docs.auth0.com/refresh-token

Pero nuevamente, para implementar esto (sin Auth0) necesitaría almacenar tokens de actualización y mantener su caducidad. ¿Cuál es el beneficio real entonces? ¿Por qué no tener solo un token (no JWT) y mantener la caducidad en el servidor?

¿Hay otras opciones? ¿El uso de JWT no es adecuado para este escenario?


¿Qué hay de este enfoque:

  • Para cada solicitud de cliente, el servidor compara el tiempo de expiración del token con (currentTime - lastAccessTime)
  • Si expirationTime <(currentTime - lastAccessedTime) , cambia el último lastAccessedTime a currentTime.
  • En caso de inactividad en el navegador durante un período de tiempo superior a expirationTime o en caso de que la ventana del navegador se haya cerrado y expirationTime> (currentTime - lastAccessedTime) , el servidor pueda vencer el token y solicitar al usuario que inicie sesión nuevamente.

No requerimos un punto final adicional para actualizar el token en este caso. Agradecería cualquier feedack.


Buena pregunta y hay una gran cantidad de información en la pregunta en sí.

El artículo Refresh Tokens: cuándo usarlos y cómo interactúan con JWT es una buena idea para este escenario. Algunos puntos son: -

  • Los tokens de actualización llevan la información necesaria para obtener un token de acceso nuevo.
  • Los tokens de actualización también pueden caducar, pero son bastante longevos.
  • Las fichas de actualización generalmente están sujetas a estrictos requisitos de almacenamiento para garantizar que no se filtren.
  • También pueden ser incluidos en la lista negra por el servidor de autorización.

También eche un vistazo a auth0/angular-jwt angularjs

Para la API web. lea Habilitar tokens de actualización de OAuth en la aplicación AngularJS utilizando ASP .NET Web API 2 y Owin


De hecho, implementé esto en PHP usando el cliente Guzzle para crear una biblioteca cliente para la API, pero el concepto debería funcionar para otras plataformas.

Básicamente, emito dos tokens, uno corto (5 minutos) y uno largo que caduca después de una semana. La biblioteca cliente utiliza middleware para intentar una actualización del token corto si recibe una respuesta 401 a alguna solicitud. Luego, volverá a intentar la solicitud original y, si pudo actualizarla, obtendrá la respuesta correcta, de manera transparente para el usuario. Si falla, simplemente enviará el 401 al usuario.

Si el token corto está vencido, pero sigue siendo auténtico y el token largo es válido y auténtico, actualizará el token corto utilizando un punto final especial en el servicio para el cual se autentica el token largo (esto es lo único para lo que se puede usar). Luego utilizará el token corto para obtener un token largo nuevo, extendiéndolo así otra semana cada vez que se actualice el token corto.

Este enfoque también nos permite revocar el acceso en un máximo de 5 minutos, lo que es aceptable para nuestro uso sin tener que almacenar una lista negra de tokens.

Edición tardía: volviendo a leer estos meses después de que estuviera fresco en mi cabeza, debo señalar que puede revocar el acceso al actualizar el token corto porque brinda la oportunidad de realizar llamadas más caras (por ejemplo, llame a la base de datos para ver si el usuario ha sido prohibido) sin pagar en cada llamada a su servicio.


En el caso de que maneje la autenticación usted mismo (es decir, no utilice un proveedor como Auth0), lo siguiente puede funcionar:

  1. Emita el token JWT con una caducidad relativamente corta, digamos 15min.
  2. La aplicación verifica la fecha de vencimiento del token antes de cualquier transacción que requiera un token (el token contiene la fecha de vencimiento). Si el token ha caducado, primero solicita a la API que "actualice" el token (esto se hace de manera transparente a la UX).
  3. La API obtiene la solicitud de actualización del token, pero primero verifica la base de datos del usuario para ver si se ha establecido un indicador ''reautorizar'' en ese perfil de usuario (el token puede contener la identificación del usuario). Si el indicador está presente, se deniega la actualización del token; de lo contrario, se emite un token nuevo.
  4. Repetir.

El indicador ''reautorizar'' en el backend de la base de datos se establecería cuando, por ejemplo, el usuario haya restablecido su contraseña. La bandera se elimina cuando el usuario inicia sesión la próxima vez.

Además, supongamos que tiene una política por la cual un usuario debe iniciar sesión al menos una vez cada 72 horas. En ese caso, la lógica de actualización de token de su API también verificará la última fecha de inicio de sesión del usuario en la base de datos del usuario y denegará / permitirá la actualización del token sobre esa base.


Estaba cambiando de lugar cuando cambiamos nuestras aplicaciones a HTML5 con RESTful apis en el backend. La solución que se me ocurrió fue:

  1. El cliente recibe un token con un tiempo de sesión de 30 minutos (o cualquiera que sea el tiempo de sesión habitual del servidor) al iniciar sesión correctamente.
  2. Se crea un temporizador del lado del cliente para llamar a un servicio y renovar el token antes de que caduque. El nuevo token reemplazará el existente en futuras llamadas.

Como puede ver, esto reduce las frecuentes solicitudes de token de actualización. Si el usuario cierra el navegador / aplicación antes de que se active la renovación del token, el token anterior caducará a tiempo y el usuario tendrá que volver a iniciar sesión.

Se puede implementar una estrategia más complicada para atender la inactividad del usuario (por ejemplo, descuidó una pestaña abierta del navegador). En ese caso, la llamada token renovada debe incluir el tiempo de expiración esperado que no debe exceder el tiempo de sesión definido. La aplicación deberá realizar un seguimiento de la última interacción del usuario en consecuencia.

No me gusta la idea de establecer una caducidad larga, por lo que este enfoque puede no funcionar bien con aplicaciones nativas que requieren una autenticación menos frecuente.


Resolví este problema agregando una variable en los datos del token:

softexp - I set this to 5 mins (300 seconds)

Establecí la opción expiresIn a mi tiempo deseado antes de que el usuario se vea obligado a iniciar sesión nuevamente. El mío se establece en 30 minutos. Esto debe ser mayor que el valor de softexp .

Cuando mi aplicación del lado del cliente envía una solicitud a la API del servidor (donde se requiere el token, por ejemplo, la página de la lista de clientes), el servidor comprueba si el token enviado sigue siendo válido o no en función de su valor de vencimiento original ( expiresIn ). Si no es válido, el servidor responderá con un estado particular para este error, por ejemplo. INVALID_TOKEN .

Si el token sigue siendo válido según el valor expiredIn , pero ya superó el valor de softexp , el servidor responderá con un estado separado para este error, por ejemplo. EXPIRED_TOKEN :

(Math.floor(Date.now() / 1000) > decoded.softexp)

En el lado del cliente, si recibió la respuesta EXPIRED_TOKEN , debería renovar el token automáticamente enviando una solicitud de renovación al servidor. Esto es transparente para el usuario y se encarga automáticamente de la aplicación cliente.

El método de renovación en el servidor debe verificar si el token sigue siendo válido:

jwt.verify(token, secret, (err, decoded) => {})

El servidor rechazará renovar tokens si falla el método anterior.


Trabajo en Auth0 y participé en el diseño de la función token de actualización.

Todo depende del tipo de aplicación y aquí está nuestro enfoque recomendado.

aplicaciones web

Un buen patrón es actualizar el token antes de que caduque.

Establezca el vencimiento del token en una semana y actualícelo cada vez que el usuario abra la aplicación web y cada hora. Si un usuario no abre la aplicación durante más de una semana, tendrá que iniciar sesión de nuevo y esta es la aplicación web UX aceptable.

Para actualizar el token, su API necesita un nuevo punto final que reciba un JWT válido, no caducado y que devuelva el mismo JWT firmado con el nuevo campo de vencimiento. Entonces la aplicación web almacenará el token en algún lugar.

Aplicaciones móviles / nativas

La mayoría de las aplicaciones nativas se registran una sola vez.

La idea es que el token de actualización nunca caduque y se pueda intercambiar siempre por un JWT válido.

El problema con un token que nunca caduca es que nunca significa nunca. ¿Qué haces si pierdes tu teléfono? Por lo tanto, debe ser identificable por el usuario de alguna manera y la aplicación debe proporcionar una forma de revocar el acceso. Decidimos usar el nombre del dispositivo, por ejemplo, "iPad de maryo". Luego, el usuario puede ir a la aplicación y revocar el acceso al "iPad de maryo".

Otro enfoque es revocar el token de actualización en eventos específicos. Un evento interesante es cambiar la contraseña.

Creemos que JWT no es útil para estos casos de uso, por lo que usamos una cadena generada al azar y la almacenamos de nuestro lado.


Una solución alternativa para invalidar JWT, sin ningún almacenamiento seguro adicional en el backend, es implementar una nueva columna de enteros jwt_version en la tabla de usuarios. Si el usuario desea cerrar sesión o caducar los tokens existentes, simplemente incrementa el campo jwt_version .

Al generar un nuevo JWT, codifique jwt_version en la carga útil de JWT, opcionalmente incrementando el valor de antemano si el nuevo JWT debe reemplazar a todos los demás.

Al validar el JWT, el campo jwt_version se compara con el user_id y la autorización se otorga solo si coincide.