I have a cookie containing a signed jwt that is valid for 5 mins. The jwt contains basic user info (for authentication), as well as a globally unique ID (guid). I store these guids in a database if they are valid, and on the next request after expiration of the jwt, I want to:
1.) Check the database for the guid and see that it is still valid (not blacklisted)
2.) Update the jwt within the cookie with a new 5minute validity and the same information
There are many errors I've run into, but nothing I've tried has worked, and I'm curious as to whether this is even possible or the correct approach at this point.
I am using the node js packages "passport-jwt" in conjunction with "jsonwebtoken" to create the jwts and verify them.
//////////////////////
//authorization.js
//////////////////////
const JWTStrategy = require('passport-jwt').Strategy;
const jwt = require('jsonwebtoken');
const mongoose = require('mongoose');
require('../models/Guids');
const Guids = mongoose.model('Guids');
module.exports.JWTStrategy = function (passport) {
passport.use('jwt', new JWTStrategy({
jwtFromRequest: req => cookieExtractor(req, 'token'),
secretOrKey: 'secret',
passReqToCallback: true
},
(req, jwt_payload, done) => {
if (Date.now() / 1000 > jwt_payload.exp) {
Guids.findOne({ _id: jwt_payload.guid, userId: jwt_payload.uid })
.then(guid => {
if (guid.valid) {
//REFRESH TOKEN HERE
//????????return done(null, jwt_payload);
} else {
//FORCE USER TO RE-AUTHENTICATE
//???????return done('access token expired');
}
})
.catch(err => {
console.log(err);
return done('failed to validate user');
});
} else {
return done(null, jwt_payload);
}
}
));
};
var cookieExtractor = function (req, tokenName) {
var token = null;
if (req && req.cookies) {
token = req.cookies[tokenName];
} else {
console.log('no cookie found');
}
return token;
};
--
/////////////////////////////
//app.js
/////////////////////////////
const express = require('express');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const passport = require('passport');
const jwt = require('jsonwebtoken');
const app = express();
require('./authorization').JWTStrategy(passport);
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(cookieParser());
//Protected Route
app.get('/xyz', passport.authenticate('jwt', {session: false}), (req, res) => {
//route logic....
});
//login Route (creates token)
app.post('/login', (req, res, next) => {
payload = {
guid: 12345678901010101',
uid: '123456789',
};
req.login(payload, { session: false }, (err) => {
if (err) {
console.log(err);
} else {
const token = jwt.sign(payload, 'secret', {expiresIn: '30s'});
res.cookie('token', token, { httpOnly: true });
res.redirect('/xyz');
};
}
}
const port = process.env.PORT || 5000;
const server = app.listen(port, () => {
console.log(`Server started on port ${port}`);
});
By default, when the token expires, the authenticate middleware on the protected route immediately throws a failure.
I would like to bypass this failure and instead execute some code in the "authorization.js" file where the comment says "REFRESH TOKEN HERE".
That line of code is never even reached because of the automatic failure! I've tried console logging before and after expiration.
I have even manually bypassed the automatic failure before, but the response object (res) which contains the cookies is not available in the passport-jwt strategy. I am a little lost on where this logic should be implemented if the designated spot is nonsensical due to it being a middleware function.
Additionally, if the protected route is a POST, and the token expired after the page was "GET"ted successfully, I would like to not impede the POST method. I would like to seamlessly refresh the token, and then move along with the POST.
function(req, res, next) { passport.authenticate(...)(req, res, next); }
See for details in section Custom Callback – 0x1C1B