express-jwt-xsrf
Version:
Express filter for jwt parsing with anti-xsrf synchronizer.
107 lines • 4.58 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const encrypt = require("crypto");
const cookies = require("cookie-parser");
const parsing = require("body-parser");
const jwtoken = require("jsonwebtoken");
/**
* axsrfWithCors implementation.
*
* Filter defined to accept cors and validate specified bearer token integrity
* according to the specified secret key and participating anti-xsrf cookie.
*
* @author Kirk Bulis
*/
function axsrfWithCors(options) {
return [
parsing.json({
limit: options.jsonLimit || 64 * 1024,
}),
cookies('', {
decode: (value) => {
return value;
}
}),
(req, res, next) => {
res.header('Access-Control-Allow-Headers', req.header('Access-Control-Request-Headers'));
res.header('Access-Control-Allow-Origin', options.allowOrigin ? options.allowOrigin === '*' ? req.header('Origin') : options.allowOrigin : '*');
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Vary', 'Origin');
if (options.debug === true) {
console.log('~ adding cors headers');
}
next();
},
(req, res, next) => {
if (options.debug === true) {
console.log('~ checking authorization token');
}
try {
let encoded = req.headers['authorization'] || '';
if (options.debug === true) {
console.log('~ authorization header value ' + encoded);
}
if (encoded.length > 6 && encoded.substr(0, 6).toLowerCase() === 'bearer') {
encoded = encoded.substr(7).trim();
}
if (encoded.length === 0) {
encoded = req.query['token'] || '';
}
if (encoded === 'null') {
encoded = '';
}
if (encoded.length !== 0) {
if (options.debug === true) {
console.log('~ parsing token ' + encoded);
}
try {
let extracted = Object.assign({}, jwtoken.verify(encoded, options.hashingSecretKey));
if (extracted.exp && extracted.exp > (+new Date / 1000)) {
if (req.cookies['axsrf'] && extracted.axsrf === encrypt.createHmac(options.hashingAlgorithm, options.hashingSecretKey).update(req.cookies['axsrf']).digest('base64')) {
options.identify(res, extracted);
next();
return;
}
else {
if (options.debug === true) {
console.log('~ authorization token not matching axsrf cookie');
}
}
}
else {
if (options.debug === true) {
console.log('~ authorization token expired');
}
}
}
catch (eX) {
if (options.debug === true) {
console.log(eX);
}
}
}
}
catch (eX) {
}
options.identify(res);
next();
},
(req, res, next) => {
if (!res.locals.generateTokenWithAxsrf) {
res.locals.generateTokenWithAxsrf = (payload, expiresIn, onlySecure) => {
const axsrf = 'a' + (Math.floor(Math.random() * 900000000000000) + 100000000000000);
res.cookie('axsrf', axsrf, {
httpOnly: true,
secure: onlySecure,
});
return jwtoken.sign(Object.assign({ axsrf: encrypt.createHmac(options.hashingAlgorithm, options.hashingSecretKey).update(axsrf).digest('base64') }, payload), options.hashingSecretKey, {
expiresIn: expiresIn,
});
};
}
next();
},
];
}
exports.axsrfWithCors = axsrfWithCors;
//# sourceMappingURL=index.js.map