You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

423 lines
14 KiB

  1. var jwt = require('../index');
  2. var fs = require('fs');
  3. var path = require('path');
  4. var expect = require('chai').expect;
  5. var assert = require('chai').assert;
  6. var ms = require('ms');
  7. describe('RS256', function() {
  8. var pub = fs.readFileSync(path.join(__dirname, 'pub.pem'));
  9. var priv = fs.readFileSync(path.join(__dirname, 'priv.pem'));
  10. var invalid_pub = fs.readFileSync(path.join(__dirname, 'invalid_pub.pem'));
  11. describe('when signing a token', function() {
  12. var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256' });
  13. it('should be syntactically valid', function() {
  14. expect(token).to.be.a('string');
  15. expect(token.split('.')).to.have.length(3);
  16. });
  17. context('asynchronous', function() {
  18. it('should validate with public key', function(done) {
  19. jwt.verify(token, pub, function(err, decoded) {
  20. assert.ok(decoded.foo);
  21. assert.equal('bar', decoded.foo);
  22. done();
  23. });
  24. });
  25. it('should throw with invalid public key', function(done) {
  26. jwt.verify(token, invalid_pub, function(err, decoded) {
  27. assert.isUndefined(decoded);
  28. assert.isNotNull(err);
  29. done();
  30. });
  31. });
  32. });
  33. context('synchronous', function() {
  34. it('should validate with public key', function() {
  35. var decoded = jwt.verify(token, pub);
  36. assert.ok(decoded.foo);
  37. assert.equal('bar', decoded.foo);
  38. });
  39. it('should throw with invalid public key', function() {
  40. var jwtVerify = jwt.verify.bind(null, token, invalid_pub)
  41. assert.throw(jwtVerify, 'invalid signature');
  42. });
  43. });
  44. });
  45. describe('when signing a token with expiration', function() {
  46. var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', expiresIn: '10m' });
  47. it('should be valid expiration', function(done) {
  48. jwt.verify(token, pub, function(err, decoded) {
  49. assert.isNotNull(decoded);
  50. assert.isNull(err);
  51. done();
  52. });
  53. });
  54. it('should be invalid', function(done) {
  55. // expired token
  56. token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', expiresIn: -1 * ms('10m') });
  57. jwt.verify(token, pub, function(err, decoded) {
  58. assert.isUndefined(decoded);
  59. assert.isNotNull(err);
  60. assert.equal(err.name, 'TokenExpiredError');
  61. assert.instanceOf(err.expiredAt, Date);
  62. assert.instanceOf(err, jwt.TokenExpiredError);
  63. done();
  64. });
  65. });
  66. it('should NOT be invalid', function(done) {
  67. // expired token
  68. token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', expiresIn: -1 * ms('10m') });
  69. jwt.verify(token, pub, { ignoreExpiration: true }, function(err, decoded) {
  70. assert.ok(decoded.foo);
  71. assert.equal('bar', decoded.foo);
  72. done();
  73. });
  74. });
  75. });
  76. describe('when signing a token with not before', function() {
  77. var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', notBefore: -10 * 3600 });
  78. it('should be valid expiration', function(done) {
  79. jwt.verify(token, pub, function(err, decoded) {
  80. assert.isNotNull(decoded);
  81. assert.isNull(err);
  82. done();
  83. });
  84. });
  85. it('should be invalid', function(done) {
  86. // not active token
  87. token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', notBefore: '10m' });
  88. jwt.verify(token, pub, function(err, decoded) {
  89. assert.isUndefined(decoded);
  90. assert.isNotNull(err);
  91. assert.equal(err.name, 'NotBeforeError');
  92. assert.instanceOf(err.date, Date);
  93. assert.instanceOf(err, jwt.NotBeforeError);
  94. done();
  95. });
  96. });
  97. it('should valid when date are equals', function(done) {
  98. Date.fix(1451908031);
  99. token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', notBefore: 0 });
  100. jwt.verify(token, pub, function(err, decoded) {
  101. assert.isNull(err);
  102. assert.isNotNull(decoded);
  103. Date.unfix();
  104. done();
  105. });
  106. });
  107. it('should NOT be invalid', function(done) {
  108. // not active token
  109. token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', notBefore: '10m' });
  110. jwt.verify(token, pub, { ignoreNotBefore: true }, function(err, decoded) {
  111. assert.ok(decoded.foo);
  112. assert.equal('bar', decoded.foo);
  113. done();
  114. });
  115. });
  116. });
  117. describe('when signing a token with audience', function() {
  118. var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', audience: 'urn:foo' });
  119. it('should check audience', function(done) {
  120. jwt.verify(token, pub, { audience: 'urn:foo' }, function(err, decoded) {
  121. assert.isNotNull(decoded);
  122. assert.isNull(err);
  123. done();
  124. });
  125. });
  126. it('should check audience in array', function(done) {
  127. jwt.verify(token, pub, { audience: ['urn:foo', 'urn:other'] }, function (err, decoded) {
  128. assert.isNotNull(decoded);
  129. assert.isNull(err);
  130. done();
  131. });
  132. });
  133. it('should throw when invalid audience', function(done) {
  134. jwt.verify(token, pub, { audience: 'urn:wrong' }, function(err, decoded) {
  135. assert.isUndefined(decoded);
  136. assert.isNotNull(err);
  137. assert.equal(err.name, 'JsonWebTokenError');
  138. assert.instanceOf(err, jwt.JsonWebTokenError);
  139. done();
  140. });
  141. });
  142. it('should throw when invalid audience in array', function(done) {
  143. jwt.verify(token, pub, { audience: ['urn:wrong', 'urn:morewrong'] }, function(err, decoded) {
  144. assert.isUndefined(decoded);
  145. assert.isNotNull(err);
  146. assert.equal(err.name, 'JsonWebTokenError');
  147. assert.instanceOf(err, jwt.JsonWebTokenError);
  148. done();
  149. });
  150. });
  151. });
  152. describe('when signing a token with array audience', function() {
  153. var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', audience: [ 'urn:foo', 'urn:bar' ] });
  154. it('should check audience', function(done) {
  155. jwt.verify(token, pub, { audience: 'urn:foo' }, function(err, decoded) {
  156. assert.isNotNull(decoded);
  157. assert.isNull(err);
  158. done();
  159. });
  160. });
  161. it('should check other audience', function(done) {
  162. jwt.verify(token, pub, { audience: 'urn:bar' }, function(err, decoded) {
  163. assert.isNotNull(decoded);
  164. assert.isNull(err);
  165. done();
  166. });
  167. });
  168. it('should check audience in array', function(done) {
  169. jwt.verify(token, pub, { audience: ['urn:foo', 'urn:other'] }, function (err, decoded) {
  170. assert.isNotNull(decoded);
  171. assert.isNull(err);
  172. done();
  173. });
  174. });
  175. it('should throw when invalid audience', function(done) {
  176. jwt.verify(token, pub, { audience: 'urn:wrong' }, function(err, decoded) {
  177. assert.isUndefined(decoded);
  178. assert.isNotNull(err);
  179. assert.equal(err.name, 'JsonWebTokenError');
  180. assert.instanceOf(err, jwt.JsonWebTokenError);
  181. done();
  182. });
  183. });
  184. it('should throw when invalid audience in array', function(done) {
  185. jwt.verify(token, pub, { audience: ['urn:wrong', 'urn:morewrong'] }, function(err, decoded) {
  186. assert.isUndefined(decoded);
  187. assert.isNotNull(err);
  188. assert.equal(err.name, 'JsonWebTokenError');
  189. assert.instanceOf(err, jwt.JsonWebTokenError);
  190. done();
  191. });
  192. });
  193. });
  194. describe('when signing a token without audience', function() {
  195. var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256' });
  196. it('should check audience', function(done) {
  197. jwt.verify(token, pub, { audience: 'urn:wrong' }, function(err, decoded) {
  198. assert.isUndefined(decoded);
  199. assert.isNotNull(err);
  200. assert.equal(err.name, 'JsonWebTokenError');
  201. assert.instanceOf(err, jwt.JsonWebTokenError);
  202. done();
  203. });
  204. });
  205. it('should check audience in array', function(done) {
  206. jwt.verify(token, pub, { audience: ['urn:wrong', 'urn:morewrong'] }, function(err, decoded) {
  207. assert.isUndefined(decoded);
  208. assert.isNotNull(err);
  209. assert.equal(err.name, 'JsonWebTokenError');
  210. assert.instanceOf(err, jwt.JsonWebTokenError);
  211. done();
  212. });
  213. });
  214. });
  215. describe('when signing a token with issuer', function() {
  216. var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', issuer: 'urn:foo' });
  217. it('should check issuer', function(done) {
  218. jwt.verify(token, pub, { issuer: 'urn:foo' }, function(err, decoded) {
  219. assert.isNotNull(decoded);
  220. assert.isNull(err);
  221. done();
  222. });
  223. });
  224. it('should check the issuer when providing a list of valid issuers', function(done) {
  225. jwt.verify(token, pub, { issuer: [ 'urn:foo', 'urn:bar' ] }, function(err, decoded) {
  226. assert.isNotNull(decoded);
  227. assert.isNull(err);
  228. done();
  229. });
  230. });
  231. it('should throw when invalid issuer', function(done) {
  232. jwt.verify(token, pub, { issuer: 'urn:wrong' }, function(err, decoded) {
  233. assert.isUndefined(decoded);
  234. assert.isNotNull(err);
  235. assert.equal(err.name, 'JsonWebTokenError');
  236. assert.instanceOf(err, jwt.JsonWebTokenError);
  237. done();
  238. });
  239. });
  240. });
  241. describe('when signing a token without issuer', function() {
  242. var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256' });
  243. it('should check issuer', function(done) {
  244. jwt.verify(token, pub, { issuer: 'urn:foo' }, function(err, decoded) {
  245. assert.isUndefined(decoded);
  246. assert.isNotNull(err);
  247. assert.equal(err.name, 'JsonWebTokenError');
  248. assert.instanceOf(err, jwt.JsonWebTokenError);
  249. done();
  250. });
  251. });
  252. });
  253. describe('when signing a token with subject', function() {
  254. var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', subject: 'subject' });
  255. it('should check subject', function(done) {
  256. jwt.verify(token, pub, { subject: 'subject' }, function(err, decoded) {
  257. assert.isNotNull(decoded);
  258. assert.isNull(err);
  259. done();
  260. });
  261. });
  262. it('should throw when invalid subject', function(done) {
  263. jwt.verify(token, pub, { subject: 'wrongSubject' }, function(err, decoded) {
  264. assert.isUndefined(decoded);
  265. assert.isNotNull(err);
  266. assert.equal(err.name, 'JsonWebTokenError');
  267. assert.instanceOf(err, jwt.JsonWebTokenError);
  268. done();
  269. });
  270. });
  271. });
  272. describe('when signing a token without subject', function() {
  273. var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256' });
  274. it('should check subject', function(done) {
  275. jwt.verify(token, pub, { subject: 'subject' }, function(err, decoded) {
  276. assert.isUndefined(decoded);
  277. assert.isNotNull(err);
  278. assert.equal(err.name, 'JsonWebTokenError');
  279. assert.instanceOf(err, jwt.JsonWebTokenError);
  280. done();
  281. });
  282. });
  283. });
  284. describe('when signing a token with jwt id', function() {
  285. var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', jwtid: 'jwtid' });
  286. it('should check jwt id', function(done) {
  287. jwt.verify(token, pub, { jwtid: 'jwtid' }, function(err, decoded) {
  288. assert.isNotNull(decoded);
  289. assert.isNull(err);
  290. done();
  291. });
  292. });
  293. it('should throw when invalid jwt id', function(done) {
  294. jwt.verify(token, pub, { jwtid: 'wrongJwtid' }, function(err, decoded) {
  295. assert.isUndefined(decoded);
  296. assert.isNotNull(err);
  297. assert.equal(err.name, 'JsonWebTokenError');
  298. assert.instanceOf(err, jwt.JsonWebTokenError);
  299. done();
  300. });
  301. });
  302. });
  303. describe('when signing a token without jwt id', function() {
  304. var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256' });
  305. it('should check jwt id', function(done) {
  306. jwt.verify(token, pub, { jwtid: 'jwtid' }, function(err, decoded) {
  307. assert.isUndefined(decoded);
  308. assert.isNotNull(err);
  309. assert.equal(err.name, 'JsonWebTokenError');
  310. assert.instanceOf(err, jwt.JsonWebTokenError);
  311. done();
  312. });
  313. });
  314. });
  315. describe('when verifying a malformed token', function() {
  316. it('should throw', function(done) {
  317. jwt.verify('fruit.fruit.fruit', pub, function(err, decoded) {
  318. assert.isUndefined(decoded);
  319. assert.isNotNull(err);
  320. assert.equal(err.name, 'JsonWebTokenError');
  321. done();
  322. });
  323. });
  324. });
  325. describe('when decoding a jwt token with additional parts', function() {
  326. var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256' });
  327. it('should throw', function(done) {
  328. jwt.verify(token + '.foo', pub, function(err, decoded) {
  329. assert.isUndefined(decoded);
  330. assert.isNotNull(err);
  331. done();
  332. });
  333. });
  334. });
  335. describe('when decoding a invalid jwt token', function() {
  336. it('should return null', function(done) {
  337. var payload = jwt.decode('whatever.token');
  338. assert.isNull(payload);
  339. done();
  340. });
  341. });
  342. describe('when decoding a valid jwt token', function() {
  343. it('should return the payload', function(done) {
  344. var obj = { foo: 'bar' };
  345. var token = jwt.sign(obj, priv, { algorithm: 'RS256' });
  346. var payload = jwt.decode(token);
  347. assert.equal(payload.foo, obj.foo);
  348. done();
  349. });
  350. it('should return the header and payload and signature if complete option is set', function(done) {
  351. var obj = { foo: 'bar' };
  352. var token = jwt.sign(obj, priv, { algorithm: 'RS256' });
  353. var decoded = jwt.decode(token, { complete: true });
  354. assert.equal(decoded.payload.foo, obj.foo);
  355. assert.deepEqual(decoded.header, { typ: 'JWT', alg: 'RS256' });
  356. assert.ok(typeof decoded.signature == 'string');
  357. done();
  358. });
  359. });
  360. });