Skip to content

Commit

Permalink
Added nbf support
Browse files Browse the repository at this point in the history
  • Loading branch information
TATDK committed Jun 26, 2015
1 parent ab76ec5 commit f26ba4e
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 1 deletion.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ encoded private key for RSA and ECDSA.

* `algorithm` (default: `HS256`)
* `expiresInMinutes` or `expiresInSeconds`
* `notBeforeMinutes` or `notBeforeSeconds`
* `audience`
* `subject`
* `issuer`
Expand All @@ -37,7 +38,7 @@ encoded private key for RSA and ECDSA.
If `payload` is not a buffer or a string, it will be coerced into a string
using `JSON.stringify`.

If any `expiresInMinutes`, `audience`, `subject`, `issuer`, `jwtid`, `subject` are not provided, there is no default. The jwt generated won't include those properties in the payload.
If any `expiresInMinutes`, `notBeforeMinutes`, `audience`, `subject`, `issuer`, `jwtid`, `subject` are not provided, there is no default. The jwt generated won't include those properties in the payload.

Additional headers can be provided via the `headers` object.

Expand All @@ -60,6 +61,7 @@ var token = jwt.sign({ foo: 'bar' }, cert, { algorithm: 'RS256'});
`options`:

* `ignoreExpiration`
* `ignoreNotBefore`
* `audience`
* `issuer`
* `jwtid`
Expand All @@ -81,6 +83,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`: if `true` do not validate the not before of the token.
* `jwtid`: if you want to check JWT ID (`jti`), provide a value here
* `subject`: if you want to check subject (`sub`), provide a value here

Expand Down
17 changes: 17 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
var jws = require('jws');

var JsonWebTokenError = module.exports.JsonWebTokenError = require('./lib/JsonWebTokenError');
var NotBeforeError = module.exports.NotBeforeError = require('./lib/NotBeforeError');
var TokenExpiredError = module.exports.TokenExpiredError = require('./lib/TokenExpiredError');

module.exports.decode = function (jwt, options) {
Expand Down Expand Up @@ -53,6 +54,14 @@ module.exports.sign = function(payload, secretOrPrivateKey, options) {
if (!options.noTimestamp) {
payload.iat = payload.iat || timestamp;
}

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

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

var expiresInSeconds = options.expiresInMinutes ?
options.expiresInMinutes * 60 :
Expand Down Expand Up @@ -167,6 +176,14 @@ module.exports.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))
return done(new NotBeforeError('jwt not active', new Date(payload.nbf * 1000)));
}

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

var NotBeforeError = function (message, date) {
JsonWebTokenError.call(this, message);
this.name = 'NotBeforeError';
this.date = date;
};

NotBeforeError.prototype = Object.create(JsonWebTokenError.prototype);

NotBeforeError.prototype.constructor = NotBeforeError;

module.exports = NotBeforeError;
37 changes: 37 additions & 0 deletions test/jwt.rs.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,43 @@ describe('RS256', function() {
});
});

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

it('should be valid expiration', function(done) {
jwt.verify(token, pub, function(err, decoded) {
assert.isNotNull(decoded);
assert.isNull(err);
done();
});
});

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

jwt.verify(token, pub, function(err, decoded) {
assert.isUndefined(decoded);
assert.isNotNull(err);
assert.equal(err.name, 'NotBeforeError');
assert.instanceOf(err.date, Date);
assert.instanceOf(err, jwt.NotBeforeError);
done();
});
});

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

jwt.verify(token, pub, { ignoreNotBefore: true }, function(err, decoded) {
assert.ok(decoded.foo);
assert.equal('bar', decoded.foo);
done();
});
});
});

describe('when signing a token with audience', function() {
var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', audience: 'urn:foo' });

Expand Down

0 comments on commit f26ba4e

Please sign in to comment.