Search code examples
javascriptjwtbackendrefresh-tokendotenv

Implementing Refresh Token


So I have read some ways to implement a Refresh Token to your website, but I could not understand it as the layout is very different from my School's project layout. Does anyone know how I could implement for my style of code? It basically follows MVC guidelines with model, routes, controllers.

jwtMiddleware.js:


//////////////////////////////////////////////////////
// REQUIRE DOTENV MODULE
//////////////////////////////////////////////////////
require("dotenv").config();

//////////////////////////////////////////////////////
// REQUIRE JWT MODULE
//////////////////////////////////////////////////////
const jwt = require("jsonwebtoken");

//////////////////////////////////////////////////////
// SET JWT CONFIGURATION
//////////////////////////////////////////////////////
const secretKey = process.env.JWT_SECRET_KEY;
const tokenDuration = process.env.JWT_EXPIRES_IN;
const tokenAlgorithm = process.env.JWT_ALGORITHM;

//////////////////////////////////////////////////////
// MIDDLEWARE FUNCTION FOR GENERATING JWT TOKEN
//////////////////////////////////////////////////////
module.exports.generateToken = (req, res, next) => {
    const payload = {
      userId: res.locals.userId,
      timestamp: new Date()
    };

   
  
    const options = {
      algorithm: tokenAlgorithm,
      expiresIn: tokenDuration,
    };
  
    const callback = (err, token) => {
      if (err) {
        console.error("Error jwt:", err);
        res.status(500).json(err);
      } else {
        res.locals.token = token;
        next();
      }
    };
  
    const token = jwt.sign(payload, secretKey, options, callback);
  };

//////////////////////////////////////////////////////
// MIDDLEWARE FUNCTION FOR SENDING JWT TOKEN
//////////////////////////////////////////////////////
module.exports.sendToken = (req, res, next) => {
    res.status(200).json({
      message: res.locals.message,
      token: res.locals.token,
    });
  };

//////////////////////////////////////////////////////
// MIDDLEWARE FUNCTION FOR VERIFYING JWT TOKEN
//////////////////////////////////////////////////////
module.exports.verifyToken = (req, res, next) => {
    const authHeader = req.headers.authorization;
  console.log("hi")
    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      return res.status(401).json({ error: 'No token provided' });
    }
  
    const token = authHeader.substring(7);
  
    if (!token) {
      return res.status(401).json({ error: "No token provided" });
    }
  
    const callback = (err, decoded) => {
      if (err) {
        return res.status(401).json({ error: "Invalid token" });
      }
  console.log(decoded.userId)
      res.locals.userId = decoded.userId;
      res.locals.tokenTimestamp = decoded.timestamp;
      
  
      next();
    };
  
    jwt.verify(token, secretKey, callback);
  };

.env:

JWT_EXPIRES_IN=50m
JWT_ALGORITHM=HS256
REFRESH_TOKEN_EXPIRES_IN=7d

mainRoutes.js:



router.post("/login", userController.login, bcryptMiddleware.comparePassword, jwtMiddleware.generateToken, jwtMiddleware.sendToken);

router.post("/register", userController.checkUsernameOrEmailExist, bcryptMiddleware.hashPassword, userController.register, userController.login, jwtMiddleware.generateToken, jwtMiddleware.sendToken);

I tried setting the token refresh to expire after 7 days. And then make the access token last for 1 min. Added another controller where after however long the access token lasts, so then when it expires, It will instead use the Refresh Token Instead. But that is probably the wrong way of doing it as I do not understand how to really implement it


Solution

  • here's a gist hope it helps

    the access token is the one to have a short lifespan eg 15 minutes. the refresh token has the long lifespan eg 30 days.

    when a user logs in they should recieve both an access token and refresh token, store these securely (not as plain text in localstorage, use a secure cookie and encryption) and avoid exposing them in client side code as much as possible.

    when an api request is made the access token should be sent in the header

    the endpoint should validate the token, if expired it should respond that the access token has expired

    then the client should then look at the 'token expired' response and try to get an updated access token by requesting one to the endpoint with the refresh token

    the api should then respond with the new access token or a refresh token expired error

    if the refresh token has expired the user should be prompted to login again

    there are some good guides one the first page of google, I'd recommend checking out one that works for you.