Implement angular and express-jwt update tokens

I want to implement the concept of “Expiration Slide” using json tokens using angular, nodejs and express-jwt. I am a bit confused about how to do this, and I am struggling to find some example of update tokens or other materials related to sessions with these technologies / structures.

A few options that I thought of were

  • Creating a new token with each request after the initial login
  • Server-side issued token tracking

But I'm honestly not sure, please help

+6
source share
1 answer

I managed to implement this scenario.

What I've done...

On server:

-Lucky API endpoint for login. This endpoint will respond with a Json Web Token in the header. The client side should catch it (using the $ http hooks) and save it (I use local storage). The client will also manage updated tokens sent by the server.

- Each request to the server sets up the middleware in the expression for checking the token. At first I tried the express-jwt module, but the jsonwebtoken was right for me.

For certain routes, you can disable middleware. In this case, signin and signout.

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

- Middleware verification JWT always responds with a token in the header. If the token needs to be updated, the updated function is called.

jwtLib is my own library where the code runs to create, update and retrieve jwt tokens.

 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' }); } }; 

- Update function (jwtLib). Since an argument requires a decoded token, see above that jsonwebtoken allows decoding when jwt.verify () is called.

If you create a token with the expiration of 4 hours and expire an update of 1 hour (1 * 60 * 60 = 3600 seconds), this means that the token will be updated if the user is inactive for 3 hours or more, but no more than 4 hours, because in this case the verification process will fail (1 hour refreshment). This avoids generating a new token for each request only if the token expires in this time window.

 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; } }; 

On the client (Angularjs):

-Remove the client side to enter. This invokes the server endpoint. I am using Http Basic Authentication encoded with base64. You can use the base64 angular module to encode email: password Please note that upon successful execution I do not save the token to localStorage or Cookie. This will be managed by the http Interceptor.

 //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}); 

-Set http-interceptors to send a token to the server for each request and save the token in the response. If an updated token is received, it must be saved.

 // 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); } }; } ]); } ]); 
+12
source

Source: https://habr.com/ru/post/977255/


All Articles