JWT UnauthorizedError: No authorization token was found (GET request with cookie)

24,377

I visit the / or /foo route (unprotected as specified with unless), and browser displays correct result, but the console still throws the UnauthorizedError. Why is the error showing in the console if I explicitly marked this as unprotected route with "unless"?

By specifiying unless, you made the / and /foo route unprotected from app.use("/", expressJWT(...) only, not from subsequent middlewares. The request will pass to your custom middlware too.

I visit /bar route (protected), my middleware is not being called, I get the UnauthorizedError both in console and the browser. How do I make sure the middleware does get triggered here, and how do I provide the access to this route if the token is indeed found and verified in my middleware?

Because, the application got crashed at app.use("/", expressJWT(...)), when it could not find authorization token. Hence, it could not reach to your custom middleware.

Possible solution : 1

Since JWT token is stored in cookie in your case, you can set getToken method to get the token and let express-jwt to verify it, and remove your custom middleware altogether.

e.g.

app.use("/", expressJWT({
  secret : app.get('secret'),
  getToken: function fromCookie (req) {
    var token = req.cookies.access_token || req.body.access_token || req.query.access_token || req.headers['x-access-token'] ;
    if (token) {
      return token;
    } 
    return null;
  }
}).unless({
    path:[
      '/',
      '/foo',
      '/login'
    ]}
));

and handle the error

app.use(function (err, req, res, next) {
  if (err.name === 'UnauthorizedError') {
    return res.status(403).send({
      success: false,
      message: 'No token provided.'
    });
  }
});

Possible Solution : 2

You can do the custom jwt verification by implementing your custom middleware (that you have already done). Then there is no need of the following middleware at all.

Remove the following line.

app.use("/", expressJWT({secret:app.get('secret')}).unless(...)

And for protecting and unprotecting the routes, put unprotected routes before the the custom middleware and protected route after custom middleware (naive way).

Hope it helps you.

Share:
24,377

Related videos on Youtube

Ska
Author by

Ska

Updated on January 27, 2020

Comments

  • Ska
    Ska almost 3 years

    I have a strange problem, or maybe I don't understand how JWT works in Express context.

    var express = require('express')
    var app = express();
    var expressJWT = require('express-jwt');
    var jwt = require('jsonwebtoken');
    var cookieParser = require('cookie-parser');
    var bodyParser = require('body-parser');
    var unless = require('express-unless');
    app.set('secret', 'some secret');
    app.use(cookieParser());
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use("/", expressJWT({secret:app.get('secret')})
      .unless({
        path:[
          '/',
          '/foo',
          '/login'
        ]}
      ));
      // my custom route middleware to verify a token
    app.use(function(req, res, next) {
      console.log("------------------------------------");
      console.log("route middleware to verify a token");
      console.log("");
      // check header or url parameters or post parameters for token
      var token = req.body.access_token || req.query.access_token || req.headers['x-access-token'] || req.cookies.access_token;
      console.log("req.cookies.access_token:", req.cookies.access_token);
      console.log("token:", token);
      // decode token
      if (token) {
        // verifies secret and checks exp
        jwt.verify(token, app.get('secret'), function(err, decoded) {
          if (err) {
            console.log("jwt.verify ERROR")
            return res.json({ success: false, message: 'Failed to authenticate token.', err:err });
          } else {
            console.log("jwt.verify OK")
            // if everything is good, save to request for use in other routes
            req.decoded = decoded;
            next();
          }
        });
      } else {
        // if there is no token
        // return an error
        return res.status(403).send({
            success: false,
            message: 'No token provided.'
        });
      }
    });
    app.get('/', function (req, res) {
      res.send('Hello World!. /foo is open, /bar is protected. Login at /login')
    })
    app.get('/foo', function (req, res) {
      res.send('Foo')
    })
    app.get('/bar', function (req, res) {
      res.send('Foo')
    })
    app.get('/login', function (req, res) {
      var username = 'mock_username';
      var myToken = jwt.sign({username:username}, app.get('secret'));
      res.cookie('access_token', myToken).send("logged in, check cookie");
    })
    app.listen(3000, function () {
      console.log('Example app listening on port 3000!')
    })
    

    I'm setting up a JWT token and saving it to cookie in the /login route. This works and the token is set if I check cookie in the browser (dev tools in Chrome).

    • I visit the / or /foo route (unprotected as specified with unless), and browser displays correct result, but the console still throws the UnauthorizedError. Why is the error showing in the console if I explicitly marked this as unprotected route with "unless"?

    • I visit /bar route (protected), my middleware is not being called, I get the UnauthorizedError both in console and the browser. How do I make sure the middleware does get triggered here, and how do I provide the access to this route if the token is indeed found and verified in my middleware?

Related