node.jsexpressjson-web-token

Express + JWT exclude certain routes


I have an Node application running with express and jsonwebtoken. I have made a check before every request for the api calls to check the jsonwebtoken. I have manually excluded the routes like below. Is there any better way to exclude some routes from this? How can I do that?

import * as express from 'express';
import * as jwt from 'jsonwebtoken';

import UserCtrl from './controllers/user';

export default function setRoutes(app) {

  const router = express.Router();

  // route middleware to verify a token
  router.use(function (req, res, next) {
    if ((req.method == 'POST' || req.method == 'OPTIONS') && (req.url == '/user' || req.url == '/login' || req.url == '/user/activate')) {
      next();
    } else {
      // check header or url parameters or post parameters for token
      var token = req.headers.authorization;
      // decode token
      if (token) {
        // verifies secret and checks exp
        jwt.verify(token, process.env.SECRET_TOKEN, function (err, decoded) {
          if (err) {
            return res.status(401).send({
              success: false,
              message: 'Sign in to continue.'
            });
          } else {
            // if everything is good, save to request for use in other routes
            next();
          }
        });
      } else {
        // if there is no token
        // return an error
        return res.status(401).send({
          success: false,
          message: 'Sign in to continue.'
        });
      }
    }
  });

  const userCtrl = new UserCtrl();

  router.route('/login').post(userCtrl.login);
  router.route('/user/activate').post(userCtrl.activate);
  router.route('/users').get(userCtrl.getAll);
  router.route('/users/count').get(userCtrl.count);
  router.route('/user').post(userCtrl.signup);
  router.route('/user/:id').get(userCtrl.get);
  router.route('/user/:id').put(userCtrl.update);
  router.route('/user/:id').delete(userCtrl.delete);

  app.use('/api/v1', router);
}

Solution

  • You can extract the function (the one that verifies the token) and use it as a middleware for specific routes in your router. That way you don't have to specify which routes that need login inside the function.

    Like this:

    function isLoggedIn(req, res, next) {
        // check header or url parameters or post parameters for token
        var token = req.headers.authorization;
        // decode token
        if (token) {
            // verifies secret and checks exp
            jwt.verify(token, process.env.SECRET_TOKEN, function(err, decoded) {
                if (err) {
                    return res.status(401).send({
                        success: false,
                        message: 'Sign in to continue.'
                    });
                } else {
                    // if everything is good, save to request for use in other routes
                    next();
                }
            });
        } else {
            // if there is no token
            // return an error
            return res.status(401).send({
                success: false,
                message: 'Sign in to continue.'
            });
        }
    }
    
    const userCtrl = new UserCtrl();
    
    // Routes that require no login
    router.post('/login', userCtrl.login);
    router.get('/users', userCtrl.getAll);
    router.post('/user/activate', userCtrl.activate);
    
    // Routes that require login
    router.get('/users/count', isLoggedIn, userCtrl.count);
    router.post('/user', isLoggedIn, userCtrl.signup);
    router.get('/user/:id', isLoggedIn, userCtrl.get);
    router.put('/user/:id', isLoggedIn, userCtrl.update);
    router.delete('/user/:id', isLoggedIn, userCtrl.delete);
    
    app.use('/api/v1', router);
    

    You can read more about Express Middlewares here.