implementando tokens de refresco con angular y express-jwt

Quiero implementar el concepto de caducidad deslizante con tokens web json usando angular, nodejs y express-jwt. Estoy un poco confundido sobre cómo hacer esto, y estoy luchando para encontrar algún ejemplo de tokens de actualización u otro material relacionado con las sesiones con estas tecnologías / marcos.

Algunas opciones que estaba pensando eran

  • Generando un nuevo token con cada solicitud después del inicio de sesión inicial
  • Realizar un seguimiento del token emitido en el lado del servidor a lo largo de

Pero sinceramente no estoy seguro, por favor ayuda

Me las arreglé para implementar este escenario.

Qué he hecho…

En el servidor:

-Habilitar un punto final de API para el inicio de sesión. Este punto final responderá con el token web Json en el encabezado. El lado del cliente debe capturarlo (con $ interceptores http) y guardarlo (uso el almacenamiento local). El cliente también administrará los tokens actualizados enviados por el servidor.

-En cada solicitud al servidor, configure un middleware en Express para validar el token. Al principio probé el módulo express-jwt pero jsonwebtoken era el correcto para mí.

Para rutas específicas es posible que desee deshabilitar el middleware. En este caso, iniciar sesión y cerrar sesión.

var jwtCheck = auth.verifyJWT; jwtCheck.unless = unless; app.use('/api', jwtCheck.unless({path: [ '/api/auth/signin', '/api/auth/signout' ]})); 

-El middleware VerifyJWT siempre responde con un token en el encabezado. Si el token necesita actualizarse, se llama a una función renovada.

jwtLib es mi propia biblioteca donde reside el código para crear, actualizar y recuperar tokens jwt.

 function(req, res, next) { var newToken, token = jwtLib.fetch(req.headers); if(token) { jwt.verify(token, config.jwt.secret, { secret: config.jwt.secret }, function(err, decoded) { if(err) { return res.status(401).send({ message: 'User token is not valid' }); } //Refresh: If the token needs to be refreshed gets the new refreshed token newToken = jwtLib.refreshToken(decoded); if(newToken) { // Set the JWT refreshed token in http header res.set('Authorization', 'Bearer ' + newToken); next(); } else { res.set('Authorization', 'Bearer ' + token); next(); } }); } else { return res.status(401).send({ message: 'User token is not present' }); } }; 

-La función de actualización (jwtLib). Como el argumento necesita un token descodificado, vea más arriba que jsonwebtoken resuelve un descifrado cuando se llama a jwt.verify ().

Si crea durante el inicio de sesión un token con un vencimiento de 4 horas y tiene un vencimiento de actualización de 1 h (1 * 60 * 60 = 3600 segundos), eso significa que el token se actualizará si el usuario ha estado inactivo durante 3 horas o más. , pero no por más de 4 horas, porque el proceso de verificación fallaría en este caso (1 hora de actualización). Esto evita generar un nuevo token en cada solicitud, solo si el token caducará en esta ventana de tiempo.

 module.exports.refreshToken = function(decoded) { var token_exp, now, newToken; token_exp = decoded.exp; now = moment().unix().valueOf(); if((token_exp - now) < config.jwt.TOKEN_REFRESH_EXPIRATION) { newToken = this.createToken(decoded.user); if(newToken) { return newToken; } } else { return null; } }; 

En el cliente (Angularjs):

-Habilitar un lado del cliente para iniciar sesión. Esto llama al punto final del servidor. Yo uso la autenticación básica HTTP codificada con base64. Puede usar el módulo angular base64 para codificar el correo electrónico: contraseña Tenga en cuenta que, en caso de éxito, no almaceno el token en el almacenamiento local o en la cookie. Esto será gestionado por el interceptor http.

 //Base64 encode Basic Authorization (email:password) $http.defaults.headers.common.Authorization = 'Basic ' + base64.encode(credentials.email + ':' + credentials.password); return $http.post('/api/auth/signin', {skipAuthorization: true}); 

-Configure los interceptores http para enviar el token al servidor en cada solicitud y almacenar el token en la respuesta. Si se recibe un token actualizado, este debe almacenarse.

 // Config HTTP Interceptors angular.module('auth').config(['$httpProvider', function($httpProvider) { // Set the httpProvider interceptor $httpProvider.interceptors.push(['$q', '$location', 'localStorageService', 'jwtHelper', '$injector', function($q, $location, localStorageService, jwtHelper, $injector) { return { request: function(config) { var token = localStorageService.get('authToken'); config.headers = config.headers || {}; if (token && !jwtHelper.isTokenExpired(token)) { config.headers.Authorization = 'Bearer ' + token; } return config; }, requestError: function(rejection) { return $q.reject(rejection); }, response: function(response) { //JWT Token: If the token is a valid JWT token, new or refreshed, save it in the localStorage var Authentication = $injector.get('Authentication'), storagedToken = localStorageService.get('authToken'), receivedToken = response.headers('Authorization'); if(receivedToken) { receivedToken = Authentication.fetchJwt(receivedToken); } if(receivedToken && !jwtHelper.isTokenExpired(receivedToken) && (storagedToken !== receivedToken)) { //Save Auth token to local storage localStorageService.set('authToken', receivedToken); } return response; }, responseError: function(rejection) { var Authentication = $injector.get('Authentication'); switch (rejection.status) { case 401: // Deauthenticate the global user Authentication.signout(); break; case 403: // Add unauthorized behaviour break; } return $q.reject(rejection); } }; } ]); } ]);