Made verify truly asynchronous or synchronous, Zalgo has been contained!

This commit is contained in:
Thomas Payne
2014-12-12 16:45:19 +00:00
parent eea72087db
commit 0acfe4f503
3 changed files with 68 additions and 23 deletions
+15 -2
View File
@@ -47,9 +47,11 @@ var cert = fs.readFileSync('private.key'); // get private key
var token = jwt.sign({ foo: 'bar' }, cert, { algorithm: 'RS256'});
```
### jwt.verify(token, secretOrPublicKey, options, callback)
### jwt.verify(token, secretOrPublicKey, [options, callback])
(Synchronous with callback) Returns the payload decoded if the signature (and optionally expiration, audience, issuer) are valid. If not, it will return the error.
(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.
(Synchronous) If a callback is not supplied, function acts synchronously. Returns the payload decoded if the signature (and optionally expiration, audience, issuer) are valid. If not, it will throw the error.
`token` is the JsonWebToken string
@@ -62,11 +64,22 @@ encoded public key for RSA and ECDSA.
* `issuer`: if you want to check issuer (`iss`), provide a value here
```js
// verify a token symmetric - synchronous
var decoded = jwt.verify(token, 'shhhhh');
console.log(decoded.foo) // bar
// verify a token symmetric
jwt.verify(token, 'shhhhh', function(err, decoded) {
console.log(decoded.foo) // bar
});
// invalid token - synchronous
try {
var decoded = jwt.verify(token, 'wrong-secret');
} catch(err) {
// err
}
// invalid token
jwt.verify(token, 'wrong-secret', function(err, decoded) {
// err
+29 -11
View File
@@ -38,41 +38,59 @@ module.exports.sign = function(payload, secretOrPrivateKey, options) {
};
module.exports.verify = function(jwtString, secretOrPublicKey, options, callback) {
if ((typeof options === 'function') && !callback) callback = options;
if ((typeof options === 'function') && !callback) {
callback = options;
options = {};
}
if (!options) options = {};
if (callback) {
var done = function() {
var args = Array.prototype.slice.call(arguments, 0)
return process.nextTick(function() {
callback.apply(null, args)
});
};
} else {
var done = function(err, data) {
if (err) throw err;
return data;
};
}
if (!jwtString)
return callback(new JsonWebTokenError('jwt must be provided'));
return done(new JsonWebTokenError('jwt must be provided'));
var parts = jwtString.split('.');
if (parts.length !== 3)
return callback(new JsonWebTokenError('jwt malformed'));
return done(new JsonWebTokenError('jwt malformed'));
if (parts[2].trim() === '' && secretOrPublicKey)
return callback(new JsonWebTokenError('jwt signature is required'));
return done(new JsonWebTokenError('jwt signature is required'));
var valid;
try {
valid = jws.verify(jwtString, secretOrPublicKey);
}
catch (e) {
return callback(e);
return done(e);
}
if (!valid)
return callback(new JsonWebTokenError('invalid signature'));
return done(new JsonWebTokenError('invalid signature'));
var payload;
try {
payload = this.decode(jwtString);
} catch(err) {
return callback(err);
return done(err);
}
if (payload.exp) {
if (Math.floor(Date.now() / 1000) >= payload.exp)
return callback(new TokenExpiredError('jwt expired', new Date(payload.exp * 1000)));
return done(new TokenExpiredError('jwt expired', new Date(payload.exp * 1000)));
}
if (options.audience) {
@@ -82,15 +100,15 @@ module.exports.verify = function(jwtString, secretOrPublicKey, options, callback
var match = target.some(function(aud) { return audiences.indexOf(aud) != -1; });
if (!match)
return callback(new JsonWebTokenError('jwt audience invalid. expected: ' + payload.aud));
return done(new JsonWebTokenError('jwt audience invalid. expected: ' + payload.aud));
}
if (options.issuer) {
if (payload.iss !== options.issuer)
return callback(new JsonWebTokenError('jwt issuer invalid. expected: ' + payload.iss));
return done(new JsonWebTokenError('jwt issuer invalid. expected: ' + payload.iss));
}
callback(null, payload);
return done(null, payload);
};
var JsonWebTokenError = module.exports.JsonWebTokenError = function (message, error) {
+24 -10
View File
@@ -18,21 +18,35 @@ describe('RS256', function() {
expect(token.split('.')).to.have.length(3);
});
it('should validate with public key', function(done) {
jwt.verify(token, pub, function(err, decoded) {
assert.ok(decoded.foo);
assert.equal('bar', decoded.foo);
done();
context('asynchronous', function() {
it('should validate with public key', function(done) {
jwt.verify(token, pub, function(err, decoded) {
assert.ok(decoded.foo);
assert.equal('bar', decoded.foo);
done();
});
});
it('should throw with invalid public key', function(done) {
jwt.verify(token, invalid_pub, function(err, decoded) {
assert.isUndefined(decoded);
assert.isNotNull(err);
done();
});
});
});
it('should throw with invalid public key', function(done) {
jwt.verify(token, invalid_pub, function(err, decoded) {
assert.isUndefined(decoded);
assert.isNotNull(err);
done();
context('synchronous', function() {
it('should validate with public key', function() {
var decoded = jwt.verify(token, pub);
assert.ok(decoded.foo);
assert.equal('bar', decoded.foo);
});
it('should throw with invalid public key', function() {
var jwtVerify = jwt.verify.bind(null, token, invalid_pub)
assert.throw(jwtVerify, 'invalid signature');
});
});
});