Skip to content

Commit 0acfe4f

Browse files
Thomas PayneThomas Payne
Thomas Payne
authored and
Thomas Payne
committed
Made verify truly asynchronous or synchronous, Zalgo has been contained!
1 parent eea7208 commit 0acfe4f

File tree

3 files changed

+68
-23
lines changed

3 files changed

+68
-23
lines changed

README.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,11 @@ var cert = fs.readFileSync('private.key'); // get private key
4747
var token = jwt.sign({ foo: 'bar' }, cert, { algorithm: 'RS256'});
4848
```
4949

50-
### jwt.verify(token, secretOrPublicKey, options, callback)
50+
### jwt.verify(token, secretOrPublicKey, [options, callback])
5151

52-
(Synchronous with callback) Returns the payload decoded if the signature (and optionally expiration, audience, issuer) are valid. If not, it will return the error.
52+
(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.
53+
54+
(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.
5355

5456
`token` is the JsonWebToken string
5557

@@ -62,11 +64,22 @@ encoded public key for RSA and ECDSA.
6264
* `issuer`: if you want to check issuer (`iss`), provide a value here
6365

6466
```js
67+
// verify a token symmetric - synchronous
68+
var decoded = jwt.verify(token, 'shhhhh');
69+
console.log(decoded.foo) // bar
70+
6571
// verify a token symmetric
6672
jwt.verify(token, 'shhhhh', function(err, decoded) {
6773
console.log(decoded.foo) // bar
6874
});
6975

76+
// invalid token - synchronous
77+
try {
78+
var decoded = jwt.verify(token, 'wrong-secret');
79+
} catch(err) {
80+
// err
81+
}
82+
7083
// invalid token
7184
jwt.verify(token, 'wrong-secret', function(err, decoded) {
7285
// err

index.js

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,41 +38,59 @@ module.exports.sign = function(payload, secretOrPrivateKey, options) {
3838
};
3939

4040
module.exports.verify = function(jwtString, secretOrPublicKey, options, callback) {
41-
if ((typeof options === 'function') && !callback) callback = options;
41+
if ((typeof options === 'function') && !callback) {
42+
callback = options;
43+
options = {};
44+
}
45+
4246
if (!options) options = {};
4347

48+
if (callback) {
49+
var done = function() {
50+
var args = Array.prototype.slice.call(arguments, 0)
51+
return process.nextTick(function() {
52+
callback.apply(null, args)
53+
});
54+
};
55+
} else {
56+
var done = function(err, data) {
57+
if (err) throw err;
58+
return data;
59+
};
60+
}
61+
4462
if (!jwtString)
45-
return callback(new JsonWebTokenError('jwt must be provided'));
63+
return done(new JsonWebTokenError('jwt must be provided'));
4664

4765
var parts = jwtString.split('.');
4866
if (parts.length !== 3)
49-
return callback(new JsonWebTokenError('jwt malformed'));
67+
return done(new JsonWebTokenError('jwt malformed'));
5068

5169
if (parts[2].trim() === '' && secretOrPublicKey)
52-
return callback(new JsonWebTokenError('jwt signature is required'));
70+
return done(new JsonWebTokenError('jwt signature is required'));
5371

5472
var valid;
5573
try {
5674
valid = jws.verify(jwtString, secretOrPublicKey);
5775
}
5876
catch (e) {
59-
return callback(e);
77+
return done(e);
6078
}
6179

6280
if (!valid)
63-
return callback(new JsonWebTokenError('invalid signature'));
81+
return done(new JsonWebTokenError('invalid signature'));
6482

6583
var payload;
6684

6785
try {
6886
payload = this.decode(jwtString);
6987
} catch(err) {
70-
return callback(err);
88+
return done(err);
7189
}
7290

7391
if (payload.exp) {
7492
if (Math.floor(Date.now() / 1000) >= payload.exp)
75-
return callback(new TokenExpiredError('jwt expired', new Date(payload.exp * 1000)));
93+
return done(new TokenExpiredError('jwt expired', new Date(payload.exp * 1000)));
7694
}
7795

7896
if (options.audience) {
@@ -82,15 +100,15 @@ module.exports.verify = function(jwtString, secretOrPublicKey, options, callback
82100
var match = target.some(function(aud) { return audiences.indexOf(aud) != -1; });
83101

84102
if (!match)
85-
return callback(new JsonWebTokenError('jwt audience invalid. expected: ' + payload.aud));
103+
return done(new JsonWebTokenError('jwt audience invalid. expected: ' + payload.aud));
86104
}
87105

88106
if (options.issuer) {
89107
if (payload.iss !== options.issuer)
90-
return callback(new JsonWebTokenError('jwt issuer invalid. expected: ' + payload.iss));
108+
return done(new JsonWebTokenError('jwt issuer invalid. expected: ' + payload.iss));
91109
}
92110

93-
callback(null, payload);
111+
return done(null, payload);
94112
};
95113

96114
var JsonWebTokenError = module.exports.JsonWebTokenError = function (message, error) {

test/jwt.rs.tests.js

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,35 @@ describe('RS256', function() {
1818
expect(token.split('.')).to.have.length(3);
1919
});
2020

21-
it('should validate with public key', function(done) {
22-
jwt.verify(token, pub, function(err, decoded) {
23-
assert.ok(decoded.foo);
24-
assert.equal('bar', decoded.foo);
25-
done();
21+
context('asynchronous', function() {
22+
it('should validate with public key', function(done) {
23+
jwt.verify(token, pub, function(err, decoded) {
24+
assert.ok(decoded.foo);
25+
assert.equal('bar', decoded.foo);
26+
done();
27+
});
28+
});
29+
30+
it('should throw with invalid public key', function(done) {
31+
jwt.verify(token, invalid_pub, function(err, decoded) {
32+
assert.isUndefined(decoded);
33+
assert.isNotNull(err);
34+
done();
35+
});
2636
});
2737
});
2838

29-
it('should throw with invalid public key', function(done) {
30-
jwt.verify(token, invalid_pub, function(err, decoded) {
31-
assert.isUndefined(decoded);
32-
assert.isNotNull(err);
33-
done();
39+
context('synchronous', function() {
40+
it('should validate with public key', function() {
41+
var decoded = jwt.verify(token, pub);
42+
assert.ok(decoded.foo);
43+
assert.equal('bar', decoded.foo);
3444
});
3545

46+
it('should throw with invalid public key', function() {
47+
var jwtVerify = jwt.verify.bind(null, token, invalid_pub)
48+
assert.throw(jwtVerify, 'invalid signature');
49+
});
3650
});
3751

3852
});

0 commit comments

Comments
 (0)