Home > other >  ExpressJS authorization with JWT - Is this correct?
ExpressJS authorization with JWT - Is this correct?

Time:03-11

I have a small ExpressJS server with a login feature. Some pages are secured with self-written authenticate middleware that checks if your Json WebToken is correct.

I read that just one Json WebToken isn't secure enough and that you need a refresh token as well. So I added a Refresh Token. This is all verified on the server.

Now when the token is expired, I check if the user has a refreshToken and if so I create a new token and set it as a cookie. Like this:

const jwt = require('jsonwebtoken');
// Simple array holding the issued refreshTokens
const { refreshTokens } = require('../lib/auth.js');

module.exports.authenticateToken = function(req, res, next) {
  const token = req.cookies.token;
  const refreshToken = req.cookies.refreshToken;

  if(token === null) return res.redirect('/login');

  try {
    const verified = jwt.verify(token, process.env.TOKEN_SECRET);
    if(verified) return next();
  } catch(err) {
    try {
      const refreshInDb = refreshTokens.find(token => token === refreshToken);
      const refreshVerified = refreshInDb && jwt.verify(refreshToken, process.env.REFRESHTOKEN_SECRET);
      const newToken = jwt.sign({ email: refreshVerified.email }, process.env.TOKEN_SECRET, { expiresIn: 20 });
      res.cookie('token', newToken, { maxAge: 900000, httpOnly: true });
      return next();
    } catch(err) {
      return res.redirect('/login');
    }
  }
};

Now is this code correct & secure enough for a small webapplication? Am I missing stuff? It feels so... easy?

CodePudding user response:

Seems like you are veryfing both tokens at the same endpoint. This approach is wrong.

In your login endpoint, validate the user and password against database. If credentials are correct we respond with an access token and a refresh token

router.post('/login',
  asyncWrap(async (req, res, next) => {
    const { username, password } = req.body
    await validateUser(username, password)

    return res.json({
      access_token: generateAccessToken(), // expires in 1 hour
      refresh_token: generateRefreshToken(), // expires in 1 month
    })
  })
)

In your authenticated routes, you should validate only the access token (the user should send ONLY this one)

// middleware to validate the access token
export const validateToken = asyncWrap(async (req, res, next) => {
  const data = await verifyAccessToken(req.headers.authorization)
  req.auth = data
  next()
})

If the access token expires, the user should refresh its token. In this endpoint we will validate the refresh token and respond with two new tokens:

router.post('/refresh',
  asyncWrap(async (req, res, next) => {
    const { refresh_token } = req.body
    await verifyRefreshToken(refresh_token)

    return res.json({
      access_token: generateAccessToken(), // expires in 1 hour
      refresh_token: generateRefreshToken(), // expires in 1 month
    })
  })
)

CodePudding user response:

I read that just one Json WebToken isn't secure enough and that you need a refresh token as well. So I added a Refresh Token. This is all verified on the server.

Using refresh tokens has nothing to do with security of the JWT or access token. Refresh tokens are just a UX feature. They allow you to get new access tokens without asking the user to authorize again. Having a refresh token in your app doesn't automatically make it more secure.

Now when the token is expired, I check if the user has a refreshToken and if so I create a new token and set it as a cookie. Like this:

When implemented this way the refresh token doesn't grant any more security to your application. You could as well keep the access tokens in the db and refresh them when they are expired.

Are you sure that you need JWTs at all? It looks like you're using them as you would use a session based on cookies. It should be simpler to deal with sessions. You are using http-only cookies for your tokens so you already use it pretty much like a session.

Now is this code correct & secure enough for a small webapplication?

Secure enough is a concept that depends on the data that your application has access to. If it's nothing sensitive, and you know that your app can't really be abused by an attacker, then it is fine to have only some basic security in place.

  • Related