Unable to set Exp and Iat for JWT correctly
Asked Answered
T

4

18

I am a bit stumped by this one. I am trying to set up a valid JWT. I am using node.js with the jsonwebtoken middleware. I have followed the documentation located on the repo (located here), but I keep getting the wrong Exp and Iat. Obviously I would like to get this right so that I don't allow JWT's which has expired.

As a test I have the following code:

var token = jwt.sign({"id": user._id}, configGeneral.JWT, { expiresIn: '1h' });

var decoded = jwt.decode(token, configGeneral.JWT);

var d1 = new Date(decoded.exp);
var d2 = new Date(decoded.iat);

console.log(decoded);
console.log(d1);
console.log(d2);

The output of this is:

{ id: '56253091fe0397c80133f3e4',
  iat: 1445714161,
  exp: 1445717761 }
Sat Jan 17 1970 19:35:17 GMT+0200 (South Africa Standard Time)
Sat Jan 17 1970 19:35:14 GMT+0200 (South Africa Standard Time)

How do I get the timestamp to not reflect the javascript epoch, but rather the time 1 hour from now? (for both the iat and exp.)

Threat answered 24/10, 2015 at 19:28 Comment(0)
T
7

Based on what Krzysztof Sztompka posted, I could get the Ext to show the correct expiry date. (my original requirement was for 1 hour in the future)

To keep track of the change vs previous mistakes, I won't update the code above, so here is what I changed:

var d = new Date();

var calculatedExpiresIn = (((d.getTime()) + (60 * 60 * 1000)) - (d.getTime() - d.getMilliseconds()) / 1000);

var token = jwt.sign({"id": user._id}, configGeneral.JWT, { expiresIn: calculatedExpiresIn });

The console.log's will now show that the Ext is as I wanted it, now + 1 hour.

To get the Iat to show the correct date (after setting it in the sign function and then sanity checking it in the decode function), I had to set it as part of the payload. I got my answer here

So finally to get the Iat to show correctly I added it to the payload as shown here:

var token = jwt.sign({"id": user._id, "iat": (new Date().getTime())}, configGeneral.JWT, { expiresIn: calculatedExpiresIn });

This gives an output of:

{ id: '56253091fe0397c80133f3e4',
  iat: 1445763099706,
  exp: 1445766699705 }
Sun Oct 25 2015 11:51:39 GMT+0200 (South Africa Standard Time)
Sun Oct 25 2015 10:51:39 GMT+0200 (South Africa Standard Time)

This is the unencoded JWT which I will passed back to the users when they have signed in successfully and will allow me to check whether the JWT they have to pass as every future request is still valid and hasn't expired yet.

Threat answered 25/10, 2015 at 9:20 Comment(0)
I
28

This:

new Date().getTime()

give you time in miliseconds. But time in jwt token (iat, exp) is in seconds, therefore we have to divide result by 1000.

var actualTimeInSeconds = new Date().getTime()/1000;

How to get some time in seconds from now:

(new Date().getTime() + someTimeInSeconds * 1000)/1000

If you need 1 hour from now:

(new Date().getTime() + 60 * 60 * 1000)/1000

because 1h = 60min * 60 s

And at this moment you have time in seconds from jwt token and calculated time in seconds. You should only compare this values.

Precisely in your situation you should compare jwt token time with your actual time in seconds. If jwt token expiration time is greater then actual time it means that it is still valid. From docs of jwt token:

The processing of the exp claim requires that the current date/time MUST be before the expiration date/time listed in the exp claim.

Edit:

To get coorect date from iat, multiply value by 1000 and add to new Date constructor:

new Date(iat*1000)
Iives answered 24/10, 2015 at 20:8 Comment(3)
if I take your 4th code example and feed it into expiresIn, I get the epoch plus a few days (3 Feb 1970). However, if I remove the divide by 1000 I get today's date + the 17 days and few hours of the epoch. I played around a bit but got the Ext to show the correct expiry date (see my questions's update). However, this still leaves me with an incorrect Iat.Threat
I posted the solution I came up with because it actually solves the problem I had of not getting the the Ext and Iat correctly into the JWT. I might have not have explained that part well enough and I think you might have misunderstood that requirement because of that. However, your input definitely helped me get to the right answer, thanks man! :) You are quire right that I will have to decode the JWT and then compare the seconds of the Ext with my current time to be able to determine if the JWT has expired or not.Threat
I would prefer new Date().getTime()/1000 + 60 * 60Saturnian
T
7

Based on what Krzysztof Sztompka posted, I could get the Ext to show the correct expiry date. (my original requirement was for 1 hour in the future)

To keep track of the change vs previous mistakes, I won't update the code above, so here is what I changed:

var d = new Date();

var calculatedExpiresIn = (((d.getTime()) + (60 * 60 * 1000)) - (d.getTime() - d.getMilliseconds()) / 1000);

var token = jwt.sign({"id": user._id}, configGeneral.JWT, { expiresIn: calculatedExpiresIn });

The console.log's will now show that the Ext is as I wanted it, now + 1 hour.

To get the Iat to show the correct date (after setting it in the sign function and then sanity checking it in the decode function), I had to set it as part of the payload. I got my answer here

So finally to get the Iat to show correctly I added it to the payload as shown here:

var token = jwt.sign({"id": user._id, "iat": (new Date().getTime())}, configGeneral.JWT, { expiresIn: calculatedExpiresIn });

This gives an output of:

{ id: '56253091fe0397c80133f3e4',
  iat: 1445763099706,
  exp: 1445766699705 }
Sun Oct 25 2015 11:51:39 GMT+0200 (South Africa Standard Time)
Sun Oct 25 2015 10:51:39 GMT+0200 (South Africa Standard Time)

This is the unencoded JWT which I will passed back to the users when they have signed in successfully and will allow me to check whether the JWT they have to pass as every future request is still valid and hasn't expired yet.

Threat answered 25/10, 2015 at 9:20 Comment(0)
W
5

The epoch created by the library is Unix epoch time & you can check the jwt iat & exp values in any website (like this for example) & you will find them valid

For example, the iat in your question 1445714161 is GMT: Saturday, 24 October 2015 19:16:01

You exp was 1445717761 which is GMT: Saturday, 24 October 2015 20:16:01

So it was 1 hour later which was your objective from the beginning

if you try in javascript new Date(1445714161) you will get a wrong time

So the easiest way to create the iat (created automatically) & exp claims as per the documentation of the jsonwebtoken library here

You can set the expiry easily this way

jwt.sign({
  data: 'foobar'
}, 'secret', { expiresIn: 60 * 60 });

or even better:

jwt.sign({
  data: 'foobar'
}, 'secret', { expiresIn: '1h' });

This will put the exp claim in the jwt as follows, with the correct unix epoch time for both iat & exp (with expiry 1 hour later than issued at time), so for example it will be like this (which can be verified easily in jwt libraries):

{
  "data": "foobar",
  "iat": 1539549664,
  "exp": 1539553264
}

Note that the above expiresIn option is specific for jsonwebtoken library & a more generic way will be like this:

jwt.sign({
  exp: Math.floor(Date.now() / 1000) + (60 * 60),
  data: 'foobar'
}, 'secret');
Westwardly answered 14/10, 2018 at 21:13 Comment(0)
A
0

By adding *1000 to the exp and iat, you will see the right dates.

var d1 = new Date(decoded.exp*1000);
var d2 = new Date(decoded.iat*1000);

Avesta answered 16/12, 2019 at 13:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.