Skip to content

Commit

Permalink
Added support for subject and jwt id
Browse files Browse the repository at this point in the history
  • Loading branch information
TATDK committed Jun 26, 2015
1 parent 33b326f commit ab76ec5
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 1 deletion.
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ encoded private key for RSA and ECDSA.
* `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 `expiresInMinutes`, `audience`, `subject`, `issuer` are not provided, there is no default. The jwt generated won't include those properties in the payload.
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.

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

Expand All @@ -60,6 +62,8 @@ var token = jwt.sign({ foo: 'bar' }, cert, { algorithm: 'RS256'});
* `ignoreExpiration`
* `audience`
* `issuer`
* `jwtid`
* `subject`


(Asynchronous) If a callback is supplied, function acts asynchronously. Callback passed the payload decoded if the signature (and optionally expiration, audience, issuer) are valid. If not, it will be passed the error.
Expand All @@ -77,6 +81,8 @@ 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.
* `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
Expand Down Expand Up @@ -119,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) {
Expand Down Expand Up @@ -188,6 +206,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) {
Expand Down
13 changes: 13 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ module.exports.sign = function(payload, secretOrPrivateKey, options) {
if (options.subject)
payload.sub = options.subject;

if (options.jwtid)
payload.jti = options.jwtid;

var encoding = 'utf8';
if (options.encoding) {
encoding = options.encoding;
Expand Down Expand Up @@ -188,5 +191,15 @@ module.exports.verify = function(jwtString, secretOrPublicKey, options, callback
return done(new JsonWebTokenError('jwt issuer invalid. expected: ' + options.issuer));
}

if (options.subject) {
if (payload.sub !== options.subject)
return done(new JsonWebTokenError('jwt subject invalid. expected: ' + options.subject));
}

if (options.jwtid) {
if (payload.jti !== options.jwtid)
return done(new JsonWebTokenError('jwt id invalid. expected: ' + options.jwtid));
}

return done(null, payload);
};
66 changes: 66 additions & 0 deletions test/jwt.rs.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,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) {
Expand Down

0 comments on commit ab76ec5

Please sign in to comment.