0

In my NodeJS application RESTful API when user logs in I create a JWT and send it to the client in a secure, httponly cookie:

const jwt = utils.createJWT(user._id.toString());
const sessionId = utils.generateSessionId();

res.cookie(sessionId, jwt, { httpOnly: true, secure: true });

return res.status(200).json({ 
  userId: user._id,
  result: constants.SUCCESS
});

After login, subsequent API calls the browser automatically sends the secure cookie to the server.

I need to validate that the JWT has not expired, and if it has expired then I need to refresh the JWT.

But in the request to the server the cookie seems to be encrypted, so how do I extract the JWT to check if it has expired?

Ultimately what I'm trying to do is ensure that I can validate the JWT to see if it has expired, but I read that you should not store the JWT server-side, is this true, should I be trying to extract the JWT from the secure cookie and if so how?

Greg Lafrance
  • 768
  • 1
  • 7
  • 18

1 Answers1

0

If you have not set an expiration date for your jwt via the expires option then your jwt will never expire. I recommend storing your expiration in a .env for better security. (Read more at: How to set jwt token expiry time to maximum in nodejs?) If you want to set one here is how you can do it:

(here i am using user._id as payload data to encode)

const signToken = id => {
  return jwt.sign({ id }, process.env.JWT_SECRET_STRING, {
    expiresIn: process.env.JWT_expires_in
  });
};
const createSendToken = (user, statusCode, res) => {
  const token = signToken(user._id);
  const cookieOptions = {
    expires: new Date(
      Date.now() + process.env.JWT_COOKIE_EXPIRES_IN
    ),
    httpOnly: true
  };
  if (process.env.NODE_ENV === 'production') {
 // cookie will only sent on an encrypted connection
    cookieOptions.secure = true;
  }
  res.cookie('jwt', token, cookieOptions);

Next, as for checking if your token has expired: You can easily verify your token as well check if it has expired through jwt's verify function. I will use a promise-based approach:

const { promisify } = require('util');
// 1) verify token

const decoded = await promisify(jwt.verify)(
  req.cookies.jwt,
  process.env.JWT_SECRET_STRING
);

If you console.log(decoded) you will find the expiration time. You can handle the error as you see fit. These will be a JsonWebTokenError and a TokenExpiredError.
Also to note, jwt.verify has async and sync versions. (read more here :Node.js callback for jwt.verify())

However, remember that JWT is a stateles solution which is perfect for RESTful API. There is no need to store session state on the server. Also if a user's jwt has expired, have them login again so that a fresh jwt is issued to them. You can check their docs for further information: https://www.npmjs.com/package/jsonwebtoken

Tyler2P
  • 2,324
  • 26
  • 22
  • 31
sherryyy
  • 1
  • 2
  • I do have an expiration set on the JWT, but I do not know how to make use of that expiration. I want to also have a refresh token, but in any case the first step to me is to verify the JWT expiration works. So how to code this? The JWT is embedded in the secure, httponly cookie, so when user makes subsequent requests, and the cookie is automatically attached to the request, how to extract the JWT and verify it has not expired? Or is there something radically different I should do? – Greg Lafrance Aug 31 '23 at 19:52
  • you can set a short expiration of 5s, use the jwt.verify func and put it in a try/catch. when expired, it will give an error that i wrote above. Sorry i am not familiar with using refresh and access token method so i can't help you with that. You can read some other SO posts like: (https://stackoverflow.com/questions/27726066/jwt-refresh-token-flow) or hopefully someone more knowledgeable can help you. – sherryyy Sep 01 '23 at 10:38