Skip to content

Commit 757a16e

Browse files
committed
Exp calculated based on iat. fix #217
1 parent 2a91a02 commit 757a16e

File tree

3 files changed

+32
-30
lines changed

3 files changed

+32
-30
lines changed

lib/timespan.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
var ms = require('ms');
22

3-
module.exports = function (time) {
4-
var timestamp = Math.floor(Date.now() / 1000);
3+
module.exports = function (time, iat) {
4+
var timestamp = iat || Math.floor(Date.now() / 1000);
55

66
if (typeof time === 'string') {
77
var milliseconds = ms(time);
88
if (typeof milliseconds === 'undefined') {
99
return;
1010
}
1111
return Math.floor(timestamp + milliseconds / 1000);
12-
} else if (typeof time === 'number' ) {
12+
} else if (typeof time === 'number') {
1313
return timestamp + time;
1414
} else {
1515
return;

sign.js

+20-20
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ var jws = require('jws');
66
var sign_options_schema = Joi.object().keys({
77
expiresIn: [Joi.number().integer(), Joi.string()],
88
notBefore: [Joi.number().integer(), Joi.string()],
9-
audience: [Joi.string(), Joi.array()],
10-
algorithm: Joi.string().valid('RS256','RS384','RS512','ES256','ES384','ES512','HS256','HS384','HS512','none'),
11-
header: Joi.object(),
12-
encoding: Joi.string(),
13-
issuer: Joi.string(),
14-
subject: Joi.string(),
15-
jwtid: Joi.string(),
9+
audience: [Joi.string(), Joi.array()],
10+
algorithm: Joi.string().valid('RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512', 'HS256', 'HS384', 'HS512', 'none'),
11+
header: Joi.object(),
12+
encoding: Joi.string(),
13+
issuer: Joi.string(),
14+
subject: Joi.string(),
15+
jwtid: Joi.string(),
1616
noTimestamp: Joi.boolean()
1717
});
1818

@@ -25,9 +25,9 @@ var registered_claims_schema = Joi.object().keys({
2525

2626
var options_to_payload = {
2727
'audience': 'aud',
28-
'issuer': 'iss',
29-
'subject': 'sub',
30-
'jwtid': 'jti'
28+
'issuer': 'iss',
29+
'subject': 'sub',
30+
'jwtid': 'jti'
3131
};
3232

3333
var options_for_objects = [
@@ -40,15 +40,15 @@ var options_for_objects = [
4040
'jwtid',
4141
];
4242

43-
module.exports = function(payload, secretOrPrivateKey, options, callback) {
43+
module.exports = function (payload, secretOrPrivateKey, options, callback) {
4444
options = options || {};
4545

4646
var header = xtend({
4747
alg: options.algorithm || 'HS256',
4848
typ: typeof payload === 'object' ? 'JWT' : undefined
4949
}, options.header);
5050

51-
function failure (err) {
51+
function failure(err) {
5252
if (callback) {
5353
return callback(err);
5454
}
@@ -71,7 +71,7 @@ module.exports = function(payload, secretOrPrivateKey, options, callback) {
7171
});
7272

7373
if (invalid_options.length > 0) {
74-
return failure(new Error('invalid ' + invalid_options.join(',') + ' option for ' + (typeof payload ) + ' payload' ));
74+
return failure(new Error('invalid ' + invalid_options.join(',') + ' option for ' + (typeof payload ) + ' payload'));
7575
}
7676
}
7777

@@ -86,7 +86,7 @@ module.exports = function(payload, secretOrPrivateKey, options, callback) {
8686
var validation_result = sign_options_schema.validate(options);
8787

8888
if (validation_result.error) {
89-
return failure(validation_result.error);
89+
return failure(validation_result.error);
9090
}
9191

9292
var timestamp = payload.iat || Math.floor(Date.now() / 1000);
@@ -105,7 +105,7 @@ module.exports = function(payload, secretOrPrivateKey, options, callback) {
105105
}
106106

107107
if (typeof options.expiresIn !== 'undefined' && typeof payload === 'object') {
108-
payload.exp = timespan(options.expiresIn);
108+
payload.exp = timespan(options.expiresIn, timestamp);
109109
if (typeof payload.exp === 'undefined') {
110110
return failure(new Error('"expiresIn" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'));
111111
}
@@ -123,17 +123,17 @@ module.exports = function(payload, secretOrPrivateKey, options, callback) {
123123

124124
var encoding = options.encoding || 'utf8';
125125

126-
if(typeof callback === 'function') {
126+
if (typeof callback === 'function') {
127127
jws.createSign({
128128
header: header,
129129
privateKey: secretOrPrivateKey,
130130
payload: JSON.stringify(payload),
131131
encoding: encoding
132132
})
133-
.once('error', callback)
134-
.once('done', function(signature) {
135-
callback(null, signature);
136-
});
133+
.once('error', callback)
134+
.once('done', function (signature) {
135+
callback(null, signature);
136+
});
137137
} else {
138138
return jws.sign({header: header, payload: payload, secret: secretOrPrivateKey, encoding: encoding});
139139
}

test/iat.tests.js

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
var jwt = require('../index');
22
var expect = require('chai').expect;
33

4-
describe('iat', function() {
4+
describe('iat', function () {
55

6-
it('should work with a numeric iat not changing the expiration date', function () {
7-
var token = jwt.sign({foo: 123, iat: Math.floor(Date.now() / 1000) - 30}, '123', { expiresIn: 10 });
6+
it('should work with a exp calculated based on numeric iat', function () {
7+
var dateNow = Math.floor(Date.now() / 1000);
8+
var iat = dateNow - 30;
9+
var expiresIn = 50;
10+
var token = jwt.sign({foo: 123, iat: iat}, '123', {expiresIn: expiresIn});
811
var result = jwt.verify(token, '123');
9-
expect(result.exp).to.be.closeTo(Math.floor(Date.now() / 1000) + 10, 0.2);
12+
expect(result.exp).to.be.closeTo(iat + expiresIn, 0.2);
1013
});
1114

1215

1316
it('should throw if iat is not a number', function () {
1417
expect(function () {
15-
jwt.sign({foo: 123, iat:'hello'}, '123');
18+
jwt.sign({foo: 123, iat: 'hello'}, '123');
1619
}).to.throw(/"iat" must be a number/);
1720
});
1821

19-
20-
});
22+
});

0 commit comments

Comments
 (0)