Skip to content

Commit

Permalink
Made algorithms mandatory
Browse files Browse the repository at this point in the history
  • Loading branch information
Marcos Castany committed Jun 25, 2020
1 parent e9ed6d2 commit 304a1c5
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 33 deletions.
3 changes: 3 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ function wrapStaticSecretInCallback(secret){
module.exports = function(options) {
if (!options || !options.secret) throw new Error('secret should be set');

if (!options.algorithms) throw new Error('algorithms should be set');
if (!Array.isArray(options.algorithms)) throw new Error('algorithms must be an array');

var secretCallback = options.secret;

if (!isFunction(secretCallback)){
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"mocha": "^7.1.1"
},
"engines": {
"node": ">= 0.4.0"
"node": ">= 8.0.0"
},
"scripts": {
"test": "node_modules/.bin/mocha --reporter spec"
Expand Down
75 changes: 46 additions & 29 deletions test/jwt.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,34 @@ describe('failure tests', function () {
}
});

it('should throw if algorithms is not sent', function() {
try {
expressjwt({ secret: 'shhhh' });
} catch(e) {
assert.ok(e);
assert.equal(e.message, 'algorithms should be set');
}
});

it('should throw if algorithms is not an array', function() {
try {
expressjwt({ secret: 'shhhh', algorithms: 'foo' });
} catch(e) {
assert.ok(e);
assert.equal(e.message, 'algorithms must be an array');
}
});

it('should throw if no authorization header and credentials are required', function() {
expressjwt({secret: 'shhhh', credentialsRequired: true})(req, res, function(err) {
expressjwt({secret: 'shhhh', credentialsRequired: true, algorithms: ['HS256']})(req, res, function(err) {
assert.ok(err);
assert.equal(err.code, 'credentials_required');
});
});

it('support unless skip', function() {
req.originalUrl = '/index.html';
expressjwt({secret: 'shhhh'}).unless({path: '/index.html'})(req, res, function(err) {
expressjwt({secret: 'shhhh', algorithms: ['HS256'], algorithms: ['HS256']}).unless({path: '/index.html'})(req, res, function(err) {
assert.ok(!err);
});
});
Expand All @@ -37,15 +55,15 @@ describe('failure tests', function () {
corsReq.headers = {
'access-control-request-headers': 'sasa, sras, authorization'
};
expressjwt({secret: 'shhhh'})(corsReq, res, function(err) {
expressjwt({secret: 'shhhh', algorithms: ['HS256']})(corsReq, res, function(err) {
assert.ok(!err);
});
});

it('should throw if authorization header is malformed', function() {
req.headers = {};
req.headers.authorization = 'wrong';
expressjwt({secret: 'shhhh'})(req, res, function(err) {
expressjwt({secret: 'shhhh', algorithms: ['HS256']})(req, res, function(err) {
assert.ok(err);
assert.equal(err.code, 'credentials_bad_format');
});
Expand All @@ -54,7 +72,7 @@ describe('failure tests', function () {
it('should throw if authorization header is not Bearer', function() {
req.headers = {};
req.headers.authorization = 'Basic foobar';
expressjwt({secret: 'shhhh'})(req, res, function(err) {
expressjwt({secret: 'shhhh', algorithms: ['HS256']})(req, res, function(err) {
assert.ok(err);
assert.equal(err.code, 'credentials_bad_scheme');
});
Expand All @@ -63,15 +81,15 @@ describe('failure tests', function () {
it('should next if authorization header is not Bearer and credentialsRequired is false', function() {
req.headers = {};
req.headers.authorization = 'Basic foobar';
expressjwt({secret: 'shhhh', credentialsRequired: false})(req, res, function(err) {
expressjwt({secret: 'shhhh', algorithms: ['HS256'], credentialsRequired: false})(req, res, function(err) {
assert.ok(typeof err === 'undefined');
});
});

it('should throw if authorization header is not well-formatted jwt', function() {
req.headers = {};
req.headers.authorization = 'Bearer wrongjwt';
expressjwt({secret: 'shhhh'})(req, res, function(err) {
expressjwt({secret: 'shhhh', algorithms: ['HS256']})(req, res, function(err) {
assert.ok(err);
assert.equal(err.code, 'invalid_token');
});
Expand All @@ -80,7 +98,7 @@ describe('failure tests', function () {
it('should throw if jwt is an invalid json', function() {
req.headers = {};
req.headers.authorization = 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.yJ1c2VybmFtZSI6InNhZ3VpYXIiLCJpYXQiOjE0NzEwMTg2MzUsImV4cCI6MTQ3MzYxMDYzNX0.foo';
expressjwt({secret: 'shhhh'})(req, res, function(err) {
expressjwt({secret: 'shhhh', algorithms: ['HS256']})(req, res, function(err) {
assert.ok(err);
assert.equal(err.code, 'invalid_token');
});
Expand All @@ -92,7 +110,7 @@ describe('failure tests', function () {

req.headers = {};
req.headers.authorization = 'Bearer ' + token;
expressjwt({secret: 'different-shhhh'})(req, res, function(err) {
expressjwt({secret: 'different-shhhh', algorithms: ['HS256'] })(req, res, function(err) {
assert.ok(err);
assert.equal(err.code, 'invalid_token');
assert.equal(err.message, 'invalid signature');
Expand All @@ -101,11 +119,11 @@ describe('failure tests', function () {

it('should throw if audience is not expected', function() {
var secret = 'shhhhhh';
var token = jwt.sign({foo: 'bar', aud: 'expected-audience'}, secret);
var token = jwt.sign({foo: 'bar', aud: 'expected-audience'}, secret, { expiresIn: 500});

req.headers = {};
req.headers.authorization = 'Bearer ' + token;
expressjwt({secret: 'shhhhhh', audience: 'not-expected-audience'})(req, res, function(err) {
expressjwt({secret: 'shhhhhh', algorithms: ['HS256'], audience: 'not-expected-audience'})(req, res, function(err) {
assert.ok(err);
assert.equal(err.code, 'invalid_token');
assert.equal(err.message, 'jwt audience invalid. expected: not-expected-audience');
Expand All @@ -118,7 +136,7 @@ describe('failure tests', function () {

req.headers = {};
req.headers.authorization = 'Bearer ' + token;
expressjwt({secret: 'shhhhhh'})(req, res, function(err) {
expressjwt({secret: 'shhhhhh', algorithms: ['HS256']})(req, res, function(err) {
assert.ok(err);
assert.equal(err.code, 'invalid_token');
assert.equal(err.inner.name, 'TokenExpiredError');
Expand All @@ -132,7 +150,7 @@ describe('failure tests', function () {

req.headers = {};
req.headers.authorization = 'Bearer ' + token;
expressjwt({secret: 'shhhhhh', issuer: 'http://wrong'})(req, res, function(err) {
expressjwt({secret: 'shhhhhh', algorithms: ['HS256'], issuer: 'http://wrong'})(req, res, function(err) {
assert.ok(err);
assert.equal(err.code, 'invalid_token');
assert.equal(err.message, 'jwt issuer invalid. expected: http://wrong');
Expand All @@ -141,14 +159,13 @@ describe('failure tests', function () {

it('should use errors thrown from custom getToken function', function() {
var secret = 'shhhhhh';
var token = jwt.sign({foo: 'bar'}, secret);

function getTokenThatThrowsError() {
throw new UnauthorizedError('invalid_token', { message: 'Invalid token!' });
}

expressjwt({
secret: 'shhhhhh',
secret: 'shhhhhh', algorithms: ['HS256'],
getToken: getTokenThatThrowsError
})(req, res, function(err) {
assert.ok(err);
Expand All @@ -157,7 +174,6 @@ describe('failure tests', function () {
});
});


it('should throw error when signature is wrong', function() {
var secret = "shhh";
var token = jwt.sign({foo: 'bar', iss: 'http://www'}, secret);
Expand All @@ -170,7 +186,7 @@ describe('failure tests', function () {
// build request
req.headers = [];
req.headers.authorization = 'Bearer ' + newToken;
expressjwt({secret: secret})(req,res, function(err) {
expressjwt({secret: secret, algorithms: ['HS256']})(req,res, function(err) {
assert.ok(err);
assert.equal(err.code, 'invalid_token');
assert.equal(err.message, 'invalid token');
Expand All @@ -183,7 +199,7 @@ describe('failure tests', function () {

req.headers = {};
req.headers.authorization = 'Bearer ' + token;
expressjwt({ secret: secret, credentialsRequired: false })(req, res, function(err) {
expressjwt({ secret: secret, credentialsRequired: false, algorithms: ['HS256'] })(req, res, function(err) {
assert.ok(err);
assert.equal(err.code, 'invalid_token');
assert.equal(err.message, 'jwt expired');
Expand All @@ -196,7 +212,7 @@ describe('failure tests', function () {

req.headers = {};
req.headers.authorization = 'Bearer ' + token;
expressjwt({ secret: "not the secret", credentialsRequired: false })(req, res, function(err) {
expressjwt({ secret: "not the secret", algorithms: ['HS256'], credentialsRequired: false })(req, res, function(err) {
assert.ok(err);
assert.equal(err.code, 'invalid_token');
assert.equal(err.message, 'invalid signature');
Expand All @@ -215,7 +231,7 @@ describe('work tests', function () {

req.headers = {};
req.headers.authorization = 'Bearer ' + token;
expressjwt({secret: secret})(req, res, function() {
expressjwt({secret: secret, algorithms: ['HS256']})(req, res, function() {
assert.equal('bar', req.user.foo);
});
});
Expand All @@ -226,7 +242,7 @@ describe('work tests', function () {

req.headers = {};
req.headers.authorization = 'Bearer ' + token;
expressjwt({secret: secret, requestProperty: 'auth.token'})(req, res, function() {
expressjwt({secret: secret, algorithms: ['HS256'], requestProperty: 'auth.token'})(req, res, function() {
assert.equal('bar', req.auth.token.foo);
});
});
Expand All @@ -237,7 +253,7 @@ describe('work tests', function () {

req.headers = {};
req.headers.authorization = 'Bearer ' + token;
expressjwt({secret: secret})(req, res, function() {
expressjwt({secret: secret, algorithms: ['HS256']})(req, res, function() {
assert.equal('bar', req.user.foo);
});
});
Expand All @@ -248,7 +264,7 @@ describe('work tests', function () {

req.headers = {};
req.headers.authorization = 'Bearer ' + token;
expressjwt({secret: secret, userProperty: 'auth'})(req, res, function() {
expressjwt({secret: secret, algorithms: ['HS256'], userProperty: 'auth'})(req, res, function() {
assert.equal('bar', req.auth.foo);
});
});
Expand All @@ -261,7 +277,7 @@ describe('work tests', function () {
res = { };
req.headers = {};
req.headers.authorization = 'Bearer ' + token;
expressjwt({secret: secret, resultProperty: 'locals.user'})(req, res, function() {
expressjwt({secret: secret, algorithms: ['HS256'], resultProperty: 'locals.user'})(req, res, function() {
assert.equal('bar', res.locals.user.foo);
assert.ok(typeof req.user === 'undefined');
});
Expand All @@ -275,22 +291,22 @@ describe('work tests', function () {
res = { };
req.headers = {};
req.headers.authorization = 'Bearer ' + token;
expressjwt({secret: secret, userProperty: 'auth', resultProperty: 'locals.user'})(req, res, function() {
expressjwt({secret: secret, algorithms: ['HS256'], userProperty: 'auth', resultProperty: 'locals.user'})(req, res, function() {
assert.equal('bar', res.locals.user.foo);
assert.ok(typeof req.auth === 'undefined');
});
});

it('should work if no authorization header and credentials are not required', function() {
req = {};
expressjwt({ secret: 'shhhh', credentialsRequired: false })(req, res, function(err) {
expressjwt({ secret: 'shhhh', algorithms: ['HS256'], credentialsRequired: false })(req, res, function(err) {
assert(typeof err === 'undefined');
});
});

it('should not work if no authorization header', function() {
req = {};
expressjwt({ secret: 'shhhh' })(req, res, function(err) {
expressjwt({ secret: 'shhhh', algorithms: ['HS256'] })(req, res, function(err) {
assert(typeof err !== 'undefined');
});
});
Expand All @@ -301,7 +317,7 @@ describe('work tests', function () {
req.headers = {};
req.headers.authorization = 'Bearer ' + token;

expressjwt({secret: 'secretB'})(req, res, function(err) {
expressjwt({secret: 'secretB', algorithms: ['HS256']})(req, res, function(err) {
var index = err.stack.indexOf('UnauthorizedError: invalid signature')
assert.equal(index, 0, "Stack trace didn't include 'invalid signature' message.")
});
Expand All @@ -322,6 +338,7 @@ describe('work tests', function () {

expressjwt({
secret: secret,
algorithms: ['HS256'],
getToken: getTokenFromQuery
})(req, res, function() {
assert.equal('bar', req.user.foo);
Expand All @@ -339,7 +356,7 @@ describe('work tests', function () {

req.headers = {};
req.headers.authorization = 'Bearer ' + token;
expressjwt({secret: secretCallback})(req, res, function() {
expressjwt({secret: secretCallback, algorithms: ['HS256']})(req, res, function() {
assert.equal('bar', req.user.foo);
});
});
Expand Down
6 changes: 4 additions & 2 deletions test/multitenancy.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ describe('multitenancy', function(){
};

var middleware = expressjwt({
secret: secretCallback
secret: secretCallback,
algorithms: ['HS256']
});

it ('should retrieve secret using callback', function(){
Expand Down Expand Up @@ -59,8 +60,9 @@ describe('multitenancy', function(){
req.headers = {};
req.headers.authorization = 'Bearer ' + token;

var middleware = expressjwt({
expressjwt({
secret: secretCallback,
algorithms: ['HS256'],
isRevoked: function(req, payload, done){
done(null, true);
}
Expand Down
2 changes: 2 additions & 0 deletions test/revocation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ describe('revoked jwts', function(){

var middleware = expressjwt({
secret: secret,
algorithms: ['HS256'],
isRevoked: function(req, payload, done){
done(null, payload.jti && payload.jti === revoked_id);
}
Expand Down Expand Up @@ -54,6 +55,7 @@ describe('revoked jwts', function(){

expressjwt({
secret: secret,
algorithms: ['HS256'],
isRevoked: function(req, payload, done){
done(new Error('An error ocurred'));
}
Expand Down
2 changes: 1 addition & 1 deletion test/string_token.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe('string tokens', function () {

req.headers = {};
req.headers.authorization = 'Bearer ' + token;
expressjwt({secret: secret})(req, res, function() {
expressjwt({secret: secret, algorithms: ['HS256']})(req, res, function() {
assert.equal('foo', req.user);
});
});
Expand Down

0 comments on commit 304a1c5

Please sign in to comment.