Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable Key Lookup #41

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
});

});

});