Search code examples
node.jsexpressjwtexpress-jwt

Express.js middleware executing for a route defined above it


From what I have read here and here, the order in which you place your middleware function matters, as you can have certain routes not go through the middleware function if it is placed before the route, and the routes which are placed after will go through this middleware function.

I am seeing mixed results as my dev environment is not respecting this and my prod environment is. The code is exactly the same.

What I am trying to do is have my login route not be protected by a token checker middleware function and have the rest of my routes protected by a token.

Here is my code:

routes.get('/login', function(req, res) {
    // login user, get token
});

routes.use(function(req, res, next) {
    // check header or url parameters or post parameters for token
    var token = req.headers['access-token'];
    // decode token
    if (token) {
        // validate token
    }
    else if (req.method === 'OPTIONS') {
        next();
    }
    else {
        // if there is no token
        // return an error
        return res.status(403).send({
            success: false,
            message: 'No token provided.'
        });
    }
});

routes.get('/query/:keywords', function(req, res) {
    console.log(req.params.keywords);
    // execute query
});

app.use('/', routes);

the /query route is the only one that should have to go through the token middleware function correct? Right now I am getting the /login route also going through the token middleware function, which doesn't make sense as I shouldn't need to have a token to login.

Better yet, if there is a way to target which routes I want protected and which routes I do not want protected, this seems better than having to rely on an "order" of where the middleware function is placed.


Solution

  • First, follow along this usage in ExpressJS:

    More than one callback function can handle a route (make sure you specify the next object). For example:

    app.get('/example/b', function (req, res, next) {
      console.log('the response will be sent by the next function ...')
      next()
    }, function (req, res) {
      res.send('Hello from B!')
    })
    

    You'll notice it's definition is close to what you're declaring on routes.use(yourFunction(...)). However, there's no real reason to do it this way other than following examples you've seen in documentation, which is a good way to start nevertheless.

    However, it's a flimsy implementation, express will allow hierarchies within it's .get() .post() methods, that's correct, but this is a use case specific and not what you're looking for.

    What you need is to implement your custom auth process using the double callback configuration. do this:

    // You can save this function in a separate file and import it with require() if you want
    
    const tokenCheck = function(req, res, next) {
        // check header or url parameters or post parameters for token
        var token = req.headers['access-token'];
        // decode token
        if (token) {
            // validate token
        }
        else if (req.method === 'OPTIONS') {
            next();
        }
        else {
            // if there is no token
            // return an error
            return res.status(403).send({
                success: false,
                message: 'No token provided.'
            });
        }
    });
    
    
    routes.get('/login', function(req, res) {
        // login user, get token [Unprotected]
    });
    
    routes.get('/query/:keywords', tokenCheck, function(req, res) {
        console.log(req.params.keywords);
        // execute query [Protected with tokenCheck]
    });
    
    app.use('/', routes);
    

    You might need to play around with the code above, but it'll guide you on the right direction, this way, you can specify particular routes to execute the tokenCheck(req, res, next) function as you want.