Skip to content

Commit

Permalink
improvements to nbf and jti claims
Browse files Browse the repository at this point in the history
  • Loading branch information
jfromaniello committed Dec 28, 2015
1 parent a3c5c23 commit 46372e9
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 24 deletions.
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ encoded private key for RSA and ECDSA.

* `algorithm` (default: `HS256`)
* `expiresIn`: expressed in seconds or an string describing a time span [rauchg/ms](https://github.com/rauchg/ms.js). Eg: `60`, `"2 days"`, `"10h"`, `"7d"`
* `notBeforeMinutes` or `notBeforeSeconds`
* `notBefore`: expressed in seconds or an string describing a time span [rauchg/ms](https://github.com/rauchg/ms.js). Eg: `60`, `"2 days"`, `"10h"`, `"7d"`
* `audience`
* `subject`
* `issuer`
Expand Down Expand Up @@ -80,8 +80,7 @@ encoded public key for RSA and ECDSA.
* `audience`: if you want to check audience (`aud`), provide a value here
* `issuer`: if you want to check issuer (`iss`), provide a value here
* `ignoreExpiration`: if `true` do not validate the expiration of the token.
* `ignoreNotBefore`...
* `jwtid`: if you want to check JWT ID (`jti`), provide a value here

This comment has been minimized.

Copy link
@YouriT

YouriT Apr 14, 2016

why the reference to jwtid has been removed?

* `ignoreNotBefore`...
* `subject`: if you want to check subject (`sub`), provide a value here

```js
Expand Down
31 changes: 13 additions & 18 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var jws = require('jws');
var ms = require('ms');
var timespan = require('./lib/timespan');

var JWT = module.exports;

Expand Down Expand Up @@ -57,13 +58,12 @@ JWT.sign = function(payload, secretOrPrivateKey, options, callback) {
if (!options.noTimestamp) {
payload.iat = payload.iat || timestamp;
}

var notBeforeSeconds = options.notBeforeMinutes ?
options.notBeforeMinutes * 60 :
options.notBeforeSeconds;

if (notBeforeSeconds) {
payload.nbf = timestamp + notBeforeSeconds;

if (options.notBefore) {
payload.nbf = timespan(options.notBefore);
if (typeof payload.nbf === 'undefined') {
throw new Error('"notBefore" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60');
}
}

if (options.expiresInSeconds || options.expiresInMinutes) {
Expand All @@ -83,15 +83,8 @@ JWT.sign = function(payload, secretOrPrivateKey, options, callback) {

payload.exp = timestamp + expiresInSeconds;
} else if (options.expiresIn) {
if (typeof options.expiresIn === 'string') {
var milliseconds = ms(options.expiresIn);
if (typeof milliseconds === 'undefined') {
throw new Error('bad "expiresIn" format: ' + options.expiresIn);
}
payload.exp = timestamp + milliseconds / 1000;
} else if (typeof options.expiresIn === 'number' ) {
payload.exp = timestamp + options.expiresIn;
} else {
payload.exp = timespan(options.expiresIn);
if (typeof payload.exp === 'undefined') {
throw new Error('"expiresIn" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60');
}
}
Expand Down Expand Up @@ -211,13 +204,15 @@ JWT.verify = function(jwtString, secretOrPublicKey, options, callback) {
} catch(err) {
return done(err);
}

if (typeof payload.nbf !== 'undefined' && !options.ignoreNotBefore) {
if (typeof payload.nbf !== 'number') {
return done(new JsonWebTokenError('invalid nbf value'));
}
if (payload.nbf >= Math.floor(Date.now() / 1000))
if (payload.nbf >= Math.floor(Date.now() / 1000)) {
console.log(payload.nbf, '>=', Math.floor(Date.now() / 1000));
return done(new NotBeforeError('jwt not active', new Date(payload.nbf * 1000)));
}
}

if (typeof payload.exp !== 'undefined' && !options.ignoreExpiration) {
Expand Down
18 changes: 18 additions & 0 deletions lib/timespan.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
var ms = require('ms');

module.exports = function (time) {
var timestamp = Math.floor(Date.now() / 1000);

if (typeof time === 'string') {
var milliseconds = ms(time);
if (typeof milliseconds === 'undefined') {
return;
}
return Math.floor(timestamp + milliseconds / 1000);
} else if (typeof time === 'number' ) {
return timestamp + time;
} else {
return;
}

};
2 changes: 1 addition & 1 deletion test/expires_format.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('expires option', function() {
it('should throw if expires has a bad string format', function () {
expect(function () {
jwt.sign({foo: 123}, '123', { expiresIn: '1 monkey' });
}).to.throw(/bad "expiresIn" format: 1 monkey/);
}).to.throw(/"expiresIn" should be a number of seconds or string representing a timespan/);
});

it('should throw if expires is not an string or number', function () {
Expand Down
6 changes: 4 additions & 2 deletions test/jwt.rs.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,12 @@ describe('RS256', function() {
});

describe('when signing a token with not before', function() {
var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', notBeforeMinutes: -10 });
var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', notBefore: -10 * 3600 });

it('should be valid expiration', function(done) {
jwt.verify(token, pub, function(err, decoded) {
console.log(token);
console.dir(arguments);
assert.isNotNull(decoded);
assert.isNull(err);
done();
Expand All @@ -101,7 +103,7 @@ describe('RS256', function() {

it('should be invalid', function(done) {
// not active token
token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', notBeforeMinutes: 10 });
token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', notBefore: '10m' });

jwt.verify(token, pub, function(err, decoded) {
assert.isUndefined(decoded);
Expand Down

0 comments on commit 46372e9

Please sign in to comment.