How do I validate JWT sent to client in secure, httponly cookie?

177 Views Asked by At

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?

1

There are 1 best solutions below

2
sherryyy On

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