Merge branch 'master' of https://github.com/TATDK/node-jsonwebtoken into TATDK-master

Conflicts:
	README.md
	index.js
This commit is contained in:
José F. Romaniello
2015-12-28 13:25:39 -03:00
4 changed files with 157 additions and 2 deletions
+21 -2
View File
@@ -28,16 +28,19 @@ 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`
* `audience`
* `subject`
* `issuer`
* `jwtid`
* `subject`
* `noTimestamp`
* `headers`
If `payload` is not a buffer or a string, it will be coerced into a string
using `JSON.stringify`.
If any `expiresIn`, `audience`, `subject`, `issuer` are not provided, there is no default. The jwt generated won't include those properties in the payload.
If any `expiresIn`, `notBeforeMinutes`, `audience`, `subject`, `issuer` 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.
@@ -77,7 +80,9 @@ 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.
* `maxAge`: optional sets an expiration based on the `iat` field. Eg `2h`
* `ignoreNotBefore`...
* `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
```js
// verify a token symmetric - synchronous
@@ -120,6 +125,18 @@ jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer' }, function(
// if issuer mismatch, err == invalid issuer
});
// verify jwt id
var cert = fs.readFileSync('public.pem'); // get public key
jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid' }, function(err, decoded) {
// if jwt id mismatch, err == invalid jwt id
});
// verify subject
var cert = fs.readFileSync('public.pem'); // get public key
jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid', subject: 'subject' }, function(err, decoded) {
// if subject mismatch, err == invalid subject
});
// alg mismatch
var cert = fs.readFileSync('public.pem'); // get public key
jwt.verify(token, cert, { algorithms: ['RS256'] }, function (err, payload) {
@@ -191,6 +208,8 @@ Error object:
* 'invalid signature'
* 'jwt audience invalid. expected: [OPTIONS AUDIENCE]'
* 'jwt issuer invalid. expected: [OPTIONS ISSUER]'
* 'jwt id invalid. expected: [OPTIONS JWT ID]'
* 'jwt subject invalid. expected: [OPTIONS SUBJECT]'
```js
jwt.verify(token, 'shhhhh', function(err, decoded) {
+20
View File
@@ -4,6 +4,7 @@ var ms = require('ms');
var JWT = module.exports;
var JsonWebTokenError = JWT.JsonWebTokenError = require('./lib/JsonWebTokenError');
var NotBeforeError = module.exports.NotBeforeError = require('./lib/NotBeforeError');
var TokenExpiredError = JWT.TokenExpiredError = require('./lib/TokenExpiredError');
JWT.decode = function (jwt, options) {
@@ -56,6 +57,14 @@ 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.expiresInSeconds || options.expiresInMinutes) {
var deprecated_line;
@@ -96,6 +105,9 @@ JWT.sign = function(payload, secretOrPrivateKey, options, callback) {
if (options.subject)
payload.sub = options.subject;
if (options.jwtid)
payload.jti = options.jwtid;
var encoding = 'utf8';
if (options.encoding) {
encoding = options.encoding;
@@ -199,6 +211,14 @@ 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))
return done(new NotBeforeError('jwt not active', new Date(payload.nbf * 1000)));
}
if (typeof payload.exp !== 'undefined' && !options.ignoreExpiration) {
if (typeof payload.exp !== 'number') {
+13
View File
@@ -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;
+103
View File
@@ -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' });
@@ -236,6 +273,72 @@ describe('RS256', function() {
});
});
describe('when signing a token with subject', function() {
var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', subject: 'subject' });
it('should check subject', function() {
jwt.verify(token, pub, { subject: 'subject' }, function(err, decoded) {
assert.isNotNull(decoded);
assert.isNull(err);
});
});
it('should throw when invalid subject', function() {
jwt.verify(token, pub, { issuer: 'wrongSubject' }, function(err, decoded) {
assert.isUndefined(decoded);
assert.isNotNull(err);
assert.equal(err.name, 'JsonWebTokenError');
assert.instanceOf(err, jwt.JsonWebTokenError);
});
});
});
describe('when signing a token without subject', function() {
var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256' });
it('should check subject', function() {
jwt.verify(token, pub, { subject: 'subject' }, function(err, decoded) {
assert.isUndefined(decoded);
assert.isNotNull(err);
assert.equal(err.name, 'JsonWebTokenError');
assert.instanceOf(err, jwt.JsonWebTokenError);
});
});
});
describe('when signing a token with jwt id', function() {
var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256', jwtid: 'jwtid' });
it('should check jwt id', function() {
jwt.verify(token, pub, { jwtid: 'jwtid' }, function(err, decoded) {
assert.isNotNull(decoded);
assert.isNull(err);
});
});
it('should throw when invalid jwt id', function() {
jwt.verify(token, pub, { jwtid: 'wrongJwtid' }, function(err, decoded) {
assert.isUndefined(decoded);
assert.isNotNull(err);
assert.equal(err.name, 'JsonWebTokenError');
assert.instanceOf(err, jwt.JsonWebTokenError);
});
});
});
describe('when signing a token without jwt id', function() {
var token = jwt.sign({ foo: 'bar' }, priv, { algorithm: 'RS256' });
it('should check jwt id', function() {
jwt.verify(token, pub, { jwtid: 'jwtid' }, function(err, decoded) {
assert.isUndefined(decoded);
assert.isNotNull(err);
assert.equal(err.name, 'JsonWebTokenError');
assert.instanceOf(err, jwt.JsonWebTokenError);
});
});
});
describe('when verifying a malformed token', function() {
it('should throw', function(done) {
jwt.verify('fruit.fruit.fruit', pub, function(err, decoded) {