Skip to content
33 changes: 32 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,40 @@ ES384 | ECDSA using P-384 curve and SHA-384 hash algorithm
ES512 | ECDSA using P-521 curve and SHA-512 hash algorithm
none | No digital signature or MAC value included

## Key Lookup

```javascript
var claims = {hello: 'world'}

var keys = [
{kid: 'key1', secret: '12345'},
{kid: 'key2',secret: 'abcd'}
];
var currentKey = 0

// create a token
var token = new nJwt.Jwt(claims)
.setSigningAlgorithm('HS256')
.setSigningKey(keys[currentKey].secret)
.setSigningKeyId(keys[currentKey].kid)
.compact();

// Parse the tokent
var jwt = new nJwt.Parser().parse(token);
// lookup the key
var found = keys.find(k => k.kid === jwt.header.kid)
// then verify
var verifier = new nJwt.Verifier()
.setSigningAlgorithm('HS256')
.setSigningKey(found.secret)
.verify(token, function (err, res) {
if (res.body.hello !== claims.hello)
throw(new Error('lookup didnt work'))
});
```

## Unsupported features

The following features are not yet supported by this library:

* Encrypting the JWT (aka JWE)
* Signing key resolver (using the `kid` field)
23 changes: 18 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@ Jwt.prototype.setSigningKey = function setSigningKey(key) {
this.signingKey = key;
return this;
};
Jwt.prototype.setSigningKeyId = function setSigningKeyId(kid) {
this.header.kid = kid;
return this;
};

Jwt.prototype.setSigningAlgorithm = function setSigningAlgorithm(alg) {
if(!this.isSupportedAlg(alg)){
throw new JwtError(properties.errors.UNSUPPORTED_SIGNING_ALG);
Expand Down Expand Up @@ -258,6 +263,9 @@ Jwt.prototype.isNotBefore = function() {
};

function Parser(options){
if(!(this instanceof Parser)){
return new Parser(options);
}
return this;
}

Expand Down Expand Up @@ -328,12 +336,16 @@ Verifier.prototype.verify = function verify(jwtString,cb){

var done = handleError.bind(null,cb);

try {
jwt = new Parser().parse(jwtString);
} catch(e) {
return done(e);
if (jwtString instanceof Jwt) {
jwt = jwtString;
// console.log(jwt)
} else {
try {
jwt = new Parser().parse(jwtString);
} catch(e) {
return done(e);
}
}

var body = jwt.body;
var header = jwt.header;
var signature = jwt.signature;
Expand Down Expand Up @@ -402,6 +414,7 @@ var jwtLib = {
Jwt: Jwt,
JwtBody: JwtBody,
JwtHeader: JwtHeader,
Parser: Parser,
Verifier: Verifier,
base64urlEncode: base64urlEncode,
base64urlUnescape:base64urlUnescape,
Expand Down
9 changes: 9 additions & 0 deletions test/jwt.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ describe('Jwt',function() {
});
});

describe('.setSigningKeyId()',function(){
it('should accept a kid',function(){
var kid = '1234'
var jwt = new nJwt.Jwt({}, false)
.setSigningKeyId(kid);
assert.equal(jwt.header.kid, kid);
});
});

describe('.sign()',function(){
it('should throw if you give it an unknown algoritm',function(){
assert.throws(function(){
Expand Down
75 changes: 75 additions & 0 deletions test/key-lookup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
var assert = require('chai').assert;
var uuid = require('uuid');
var nJwt = require('../');

describe('demonstrate a key lookup on verify', function () {
describe('and given an signed token', function () {
var result;
var claims = {hello: 'world'}
var keys = [
{kid: 'key1', secret: '12345'},
{kid: 'key2',secret: 'abcd'}
];
var currentKey = 0
var expectedSecret = keys[currentKey].secret

var token = new nJwt.Jwt(claims)
.setSigningAlgorithm('HS256')
.setSigningKey(expectedSecret)
.setSigningKeyId(keys[currentKey].kid)
.compact();

var jwt = new nJwt.Parser().parse(token);
var found = keys.find(k => k.kid === jwt.header.kid)

assert.equal(found.secret, expectedSecret);

before(function (done) {
var verifier = new nJwt.Verifier()
.setSigningAlgorithm('HS256')
.setSigningKey(found.secret)
verifier.verify(token, function (err, res) {
result = [err, res];
done();
});
});

it('the jwt should be equal', function () {
assert.equal(result[1].body.hello, claims.hello);
});
});


describe('demo key lookup', function () {
var claims = {hello: 'world'}

var keys = [
{kid: 'key1', secret: '12345'},
{kid: 'key2',secret: 'abcd'}
];
var currentKey = 0

// ENCODE
// create a token
var token = new nJwt.Jwt(claims)
.setSigningAlgorithm('HS256')
.setSigningKey(keys[currentKey].secret)
.setSigningKeyId(keys[currentKey].kid)
.compact();

// DECODE
// Parse the tokent
var jwt = new nJwt.Parser().parse(token);
// lookup the key
var found = keys.find(k => k.kid === jwt.header.kid)
// then verify
var verifier = new nJwt.Verifier()
.setSigningAlgorithm('HS256')
.setSigningKey(found.secret)
.verify(token, function (err, res) {
if (res.body.hello !== claims.hello)
throw(new Error('lookup didnt work'))
});
});

});
43 changes: 43 additions & 0 deletions test/parser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
var assert = require('chai').assert;
var uuid = require('uuid');
var nJwt = require('../');


describe('Parser', function () {
it('should construct itself if called without new', function () {
assert(nJwt.Parser() instanceof nJwt.Parser);
});
});

describe('Parser.parse(token)', function () {
var result = null
var claims = { hello: 'world' }
var token = new nJwt.Jwt(claims, false)
.setSigningAlgorithm('none')
.compact();
it('should parse a valid token', function () {
var jwt = new nJwt.Parser().parse(token);
assert.equal(jwt.body.hello, claims.hello);
});

});

describe('Parser.parse(token, cb)', function () {
var result = null
var claims = { hello: 'world' }
before(function (done) {
var token = new nJwt.Jwt(claims, false)
.setSigningAlgorithm('none')
.compact();
var parser = nJwt.Parser();
parser.parse(token, function (err, res) {
result = [err, res];
done();
});
});
it('should parse a valid token', function () {
assert.isNull(result[0], 'An error was not returned');
assert.equal(result[1].body.hello, claims.hello);
});

});
23 changes: 23 additions & 0 deletions test/verifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,4 +328,27 @@ describe('Verifier().verify() ',function(){
assert.equal(result[0].userMessage,properties.errors.SIGNATURE_MISMTACH);
});
});

describe('verify an existing Jwt object', function () {
var result = null
var claims = { hello: 'world' }

before(function(done){
var token = new nJwt.Jwt(claims, false)
.setSigningAlgorithm('none')
.compact();
var jwt = new nJwt.Parser().parse(token);
var verifier = new nJwt.Verifier()
.setSigningAlgorithm('none')
verifier.verify(jwt, function(err,res){
result = [err,res];
done();
});
});
it('should accept a valid Jwt as first param', function () {
assert.equal(result[1].body.hello, claims.hello);
});

});

});