jwt.test.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. var jwt = require('jsonwebtoken');
  2. var assert = require('assert');
  3. var expressjwt = require('../lib');
  4. var UnauthorizedError = require('../lib/errors/UnauthorizedError');
  5. describe('failure tests', function () {
  6. var req = {};
  7. var res = {};
  8. it('should throw if options not sent', function() {
  9. try {
  10. expressjwt();
  11. } catch(e) {
  12. assert.ok(e);
  13. assert.equal(e.message, 'secret should be set');
  14. }
  15. });
  16. it('should throw if algorithms is not sent', function() {
  17. try {
  18. expressjwt({ secret: 'shhhh' });
  19. } catch(e) {
  20. assert.ok(e);
  21. assert.equal(e.message, 'algorithms should be set');
  22. }
  23. });
  24. it('should throw if algorithms is not an array', function() {
  25. try {
  26. expressjwt({ secret: 'shhhh', algorithms: 'foo' });
  27. } catch(e) {
  28. assert.ok(e);
  29. assert.equal(e.message, 'algorithms must be an array');
  30. }
  31. });
  32. it('should throw if no authorization header and credentials are required', function() {
  33. expressjwt({secret: 'shhhh', credentialsRequired: true, algorithms: ['HS256']})(req, res, function(err) {
  34. assert.ok(err);
  35. assert.equal(err.code, 'credentials_required');
  36. });
  37. });
  38. it('support unless skip', function() {
  39. req.originalUrl = '/index.html';
  40. expressjwt({secret: 'shhhh', algorithms: ['HS256'], algorithms: ['HS256']}).unless({path: '/index.html'})(req, res, function(err) {
  41. assert.ok(!err);
  42. });
  43. });
  44. it('should skip on CORS preflight', function() {
  45. var corsReq = {};
  46. corsReq.method = 'OPTIONS';
  47. corsReq.headers = {
  48. 'access-control-request-headers': 'sasa, sras, authorization'
  49. };
  50. expressjwt({secret: 'shhhh', algorithms: ['HS256']})(corsReq, res, function(err) {
  51. assert.ok(!err);
  52. });
  53. });
  54. it('should throw if authorization header is malformed', function() {
  55. req.headers = {};
  56. req.headers.authorization = 'wrong';
  57. expressjwt({secret: 'shhhh', algorithms: ['HS256']})(req, res, function(err) {
  58. assert.ok(err);
  59. assert.equal(err.code, 'credentials_bad_format');
  60. });
  61. });
  62. it('should throw if authorization header is not Bearer', function() {
  63. req.headers = {};
  64. req.headers.authorization = 'Basic foobar';
  65. expressjwt({secret: 'shhhh', algorithms: ['HS256']})(req, res, function(err) {
  66. assert.ok(err);
  67. assert.equal(err.code, 'credentials_bad_scheme');
  68. });
  69. });
  70. it('should next if authorization header is not Bearer and credentialsRequired is false', function() {
  71. req.headers = {};
  72. req.headers.authorization = 'Basic foobar';
  73. expressjwt({secret: 'shhhh', algorithms: ['HS256'], credentialsRequired: false})(req, res, function(err) {
  74. assert.ok(typeof err === 'undefined');
  75. });
  76. });
  77. it('should throw if authorization header is not well-formatted jwt', function() {
  78. req.headers = {};
  79. req.headers.authorization = 'Bearer wrongjwt';
  80. expressjwt({secret: 'shhhh', algorithms: ['HS256']})(req, res, function(err) {
  81. assert.ok(err);
  82. assert.equal(err.code, 'invalid_token');
  83. });
  84. });
  85. it('should throw if jwt is an invalid json', function() {
  86. req.headers = {};
  87. req.headers.authorization = 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.yJ1c2VybmFtZSI6InNhZ3VpYXIiLCJpYXQiOjE0NzEwMTg2MzUsImV4cCI6MTQ3MzYxMDYzNX0.foo';
  88. expressjwt({secret: 'shhhh', algorithms: ['HS256']})(req, res, function(err) {
  89. assert.ok(err);
  90. assert.equal(err.code, 'invalid_token');
  91. });
  92. });
  93. it('should throw if authorization header is not valid jwt', function() {
  94. var secret = 'shhhhhh';
  95. var token = jwt.sign({foo: 'bar'}, secret);
  96. req.headers = {};
  97. req.headers.authorization = 'Bearer ' + token;
  98. expressjwt({secret: 'different-shhhh', algorithms: ['HS256'] })(req, res, function(err) {
  99. assert.ok(err);
  100. assert.equal(err.code, 'invalid_token');
  101. assert.equal(err.message, 'invalid signature');
  102. });
  103. });
  104. it('should throw if audience is not expected', function() {
  105. var secret = 'shhhhhh';
  106. var token = jwt.sign({foo: 'bar', aud: 'expected-audience'}, secret, { expiresIn: 500});
  107. req.headers = {};
  108. req.headers.authorization = 'Bearer ' + token;
  109. expressjwt({secret: 'shhhhhh', algorithms: ['HS256'], audience: 'not-expected-audience'})(req, res, function(err) {
  110. assert.ok(err);
  111. assert.equal(err.code, 'invalid_token');
  112. assert.equal(err.message, 'jwt audience invalid. expected: not-expected-audience');
  113. });
  114. });
  115. it('should throw if token is expired', function() {
  116. var secret = 'shhhhhh';
  117. var token = jwt.sign({foo: 'bar', exp: 1382412921 }, secret);
  118. req.headers = {};
  119. req.headers.authorization = 'Bearer ' + token;
  120. expressjwt({secret: 'shhhhhh', algorithms: ['HS256']})(req, res, function(err) {
  121. assert.ok(err);
  122. assert.equal(err.code, 'invalid_token');
  123. assert.equal(err.inner.name, 'TokenExpiredError');
  124. assert.equal(err.message, 'jwt expired');
  125. });
  126. });
  127. it('should throw if token issuer is wrong', function() {
  128. var secret = 'shhhhhh';
  129. var token = jwt.sign({foo: 'bar', iss: 'http://foo' }, secret);
  130. req.headers = {};
  131. req.headers.authorization = 'Bearer ' + token;
  132. expressjwt({secret: 'shhhhhh', algorithms: ['HS256'], issuer: 'http://wrong'})(req, res, function(err) {
  133. assert.ok(err);
  134. assert.equal(err.code, 'invalid_token');
  135. assert.equal(err.message, 'jwt issuer invalid. expected: http://wrong');
  136. });
  137. });
  138. it('should use errors thrown from custom getToken function', function() {
  139. var secret = 'shhhhhh';
  140. function getTokenThatThrowsError() {
  141. throw new UnauthorizedError('invalid_token', { message: 'Invalid token!' });
  142. }
  143. expressjwt({
  144. secret: 'shhhhhh', algorithms: ['HS256'],
  145. getToken: getTokenThatThrowsError
  146. })(req, res, function(err) {
  147. assert.ok(err);
  148. assert.equal(err.code, 'invalid_token');
  149. assert.equal(err.message, 'Invalid token!');
  150. });
  151. });
  152. it('should throw error when signature is wrong', function() {
  153. var secret = "shhh";
  154. var token = jwt.sign({foo: 'bar', iss: 'http://www'}, secret);
  155. // manipulate the token
  156. var newContent = new Buffer("{foo: 'bar', edg: 'ar'}").toString('base64');
  157. var splitetToken = token.split(".");
  158. splitetToken[1] = newContent;
  159. var newToken = splitetToken.join(".");
  160. // build request
  161. req.headers = [];
  162. req.headers.authorization = 'Bearer ' + newToken;
  163. expressjwt({secret: secret, algorithms: ['HS256']})(req,res, function(err) {
  164. assert.ok(err);
  165. assert.equal(err.code, 'invalid_token');
  166. assert.equal(err.message, 'invalid token');
  167. });
  168. });
  169. it('should throw error if token is expired even with when credentials are not required', function() {
  170. var secret = 'shhhhhh';
  171. var token = jwt.sign({foo: 'bar', exp: 1382412921}, secret);
  172. req.headers = {};
  173. req.headers.authorization = 'Bearer ' + token;
  174. expressjwt({ secret: secret, credentialsRequired: false, algorithms: ['HS256'] })(req, res, function(err) {
  175. assert.ok(err);
  176. assert.equal(err.code, 'invalid_token');
  177. assert.equal(err.message, 'jwt expired');
  178. });
  179. });
  180. it('should throw error if token is invalid even with when credentials are not required', function() {
  181. var secret = 'shhhhhh';
  182. var token = jwt.sign({foo: 'bar', exp: 1382412921}, secret);
  183. req.headers = {};
  184. req.headers.authorization = 'Bearer ' + token;
  185. expressjwt({ secret: "not the secret", algorithms: ['HS256'], credentialsRequired: false })(req, res, function(err) {
  186. assert.ok(err);
  187. assert.equal(err.code, 'invalid_token');
  188. assert.equal(err.message, 'invalid signature');
  189. });
  190. });
  191. });
  192. describe('work tests', function () {
  193. var req = {};
  194. var res = {};
  195. it('should work if authorization header is valid jwt', function() {
  196. var secret = 'shhhhhh';
  197. var token = jwt.sign({foo: 'bar'}, secret);
  198. req.headers = {};
  199. req.headers.authorization = 'Bearer ' + token;
  200. expressjwt({secret: secret, algorithms: ['HS256']})(req, res, function() {
  201. assert.equal('bar', req.user.foo);
  202. });
  203. });
  204. it('should work with nested properties', function() {
  205. var secret = 'shhhhhh';
  206. var token = jwt.sign({foo: 'bar'}, secret);
  207. req.headers = {};
  208. req.headers.authorization = 'Bearer ' + token;
  209. expressjwt({secret: secret, algorithms: ['HS256'], requestProperty: 'auth.token'})(req, res, function() {
  210. assert.equal('bar', req.auth.token.foo);
  211. });
  212. });
  213. it('should work if authorization header is valid with a buffer secret', function() {
  214. var secret = new Buffer('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 'base64');
  215. var token = jwt.sign({foo: 'bar'}, secret);
  216. req.headers = {};
  217. req.headers.authorization = 'Bearer ' + token;
  218. expressjwt({secret: secret, algorithms: ['HS256']})(req, res, function() {
  219. assert.equal('bar', req.user.foo);
  220. });
  221. });
  222. it('should set userProperty if option provided', function() {
  223. var secret = 'shhhhhh';
  224. var token = jwt.sign({foo: 'bar'}, secret);
  225. req.headers = {};
  226. req.headers.authorization = 'Bearer ' + token;
  227. expressjwt({secret: secret, algorithms: ['HS256'], userProperty: 'auth'})(req, res, function() {
  228. assert.equal('bar', req.auth.foo);
  229. });
  230. });
  231. it('should set resultProperty if option provided', function() {
  232. var secret = 'shhhhhh';
  233. var token = jwt.sign({foo: 'bar'}, secret);
  234. req = { };
  235. res = { };
  236. req.headers = {};
  237. req.headers.authorization = 'Bearer ' + token;
  238. expressjwt({secret: secret, algorithms: ['HS256'], resultProperty: 'locals.user'})(req, res, function() {
  239. assert.equal('bar', res.locals.user.foo);
  240. assert.ok(typeof req.user === 'undefined');
  241. });
  242. });
  243. it('should ignore userProperty if resultProperty option provided', function() {
  244. var secret = 'shhhhhh';
  245. var token = jwt.sign({foo: 'bar'}, secret);
  246. req = { };
  247. res = { };
  248. req.headers = {};
  249. req.headers.authorization = 'Bearer ' + token;
  250. expressjwt({secret: secret, algorithms: ['HS256'], userProperty: 'auth', resultProperty: 'locals.user'})(req, res, function() {
  251. assert.equal('bar', res.locals.user.foo);
  252. assert.ok(typeof req.auth === 'undefined');
  253. });
  254. });
  255. it('should work if no authorization header and credentials are not required', function() {
  256. req = {};
  257. expressjwt({ secret: 'shhhh', algorithms: ['HS256'], credentialsRequired: false })(req, res, function(err) {
  258. assert(typeof err === 'undefined');
  259. });
  260. });
  261. it('should not work if no authorization header', function() {
  262. req = {};
  263. expressjwt({ secret: 'shhhh', algorithms: ['HS256'] })(req, res, function(err) {
  264. assert(typeof err !== 'undefined');
  265. });
  266. });
  267. it('should produce a stack trace that includes the failure reason', function() {
  268. var req = {};
  269. var token = jwt.sign({foo: 'bar'}, 'secretA');
  270. req.headers = {};
  271. req.headers.authorization = 'Bearer ' + token;
  272. expressjwt({secret: 'secretB', algorithms: ['HS256']})(req, res, function(err) {
  273. var index = err.stack.indexOf('UnauthorizedError: invalid signature')
  274. assert.equal(index, 0, "Stack trace didn't include 'invalid signature' message.")
  275. });
  276. });
  277. it('should work with a custom getToken function', function() {
  278. var secret = 'shhhhhh';
  279. var token = jwt.sign({foo: 'bar'}, secret);
  280. req.headers = {};
  281. req.query = {};
  282. req.query.token = token;
  283. function getTokenFromQuery(req) {
  284. return req.query.token;
  285. }
  286. expressjwt({
  287. secret: secret,
  288. algorithms: ['HS256'],
  289. getToken: getTokenFromQuery
  290. })(req, res, function() {
  291. assert.equal('bar', req.user.foo);
  292. });
  293. });
  294. it('should work with a secretCallback function that accepts header argument', function() {
  295. var secret = 'shhhhhh';
  296. var secretCallback = function(req, headers, payload, cb) {
  297. assert.equal(headers.alg, 'HS256');
  298. assert.equal(payload.foo, 'bar');
  299. process.nextTick(function(){ return cb(null, secret) });
  300. }
  301. var token = jwt.sign({foo: 'bar'}, secret);
  302. req.headers = {};
  303. req.headers.authorization = 'Bearer ' + token;
  304. expressjwt({secret: secretCallback, algorithms: ['HS256']})(req, res, function() {
  305. assert.equal('bar', req.user.foo);
  306. });
  307. });
  308. });