0
votes

I'm trying to successfully authorize using jwt and passport in node.js. I'm using passport.use with a JwtStrategy.

I have set turned on authenticate on one of my routes to test that it would unauthorize me without a token,

// Profile
router.get('/profile', passport.authenticate('jwt', { session: false }), (req, res, next) => {
    res.json({ user: req.user });
});

When I send a post request with postman to http://localhost:3000/users/profile I get Unauthorized so far so good...

When I login through postman on localhost:3000/users/authenticate with a correct username and password, I get back a token. looks like this:

{
"success":true,
"token":"JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7Il9pZCI6IjVhMzNiMzE1NDFlYWU1MDk2MDRhNTE0ZiIsIm5hbWUiOiJyYXMiLCJlbWFpbCI6InJhc0BwLmQiLCJ1c2VybmFtZSI6InJwdWxzIiwicGFzc3dvcmQiOiIkMmEkMTAkTFR5eS50TmdualB2a0htWXNuUkV0TzRwWEVEL0gycDJCYWRDRlVXMUtWaXI5TnltSUtnVUciLCJfX3YiOjB9LCJpYXQiOjE1MTMzNDI1MjksImV4cCI6MTUxMzk0NzMyOX0.amCkcFWtPwf_HYUxpXOPvcRShksH9fw7O4vVOsBm4yA",
"user":{
"id":"5a33b31541eae509604a514f",
"name":"n",
"username":"testUser",
"email":"bla@bla"}
}

I have tried to grab that token exactly like this:

JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7Il9pZCI6IjVhMzNiMzE1NDFlYWU1MDk2MDRhNTE0ZiIsIm5hbWUiOiJyYXMiLCJlbWFpbCI6InJhc0BwLmQiLCJ1c2VybmFtZSI6InJwdWxzIiwicGFzc3dvcmQiOiIkMmEkMTAkTFR5eS50TmdualB2a0htWXNuUkV0TzRwWEVEL0gycDJCYWRDRlVXMUtWaXI5TnltSUtnVUciLCJfX3YiOjB9LCJpYXQiOjE1MTMzNDI1MjksImV4cCI6MTUxMzk0NzMyOX0.amCkcFWtPwf_HYUxpXOPvcRShksH9fw7O4vVOsBm4yA

and add it as an Authorization header, but I still get Unauthorized ..... It is really difficult to proceed because I get absolute no error messages.

Here is my passport code:

const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const User = require('../models/user');
const config = require('../config/database');

module.exports = function (passport) {
    let opts = {};
    opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
    opts.secretOrKey = config.secret;
    passport.use(new JwtStrategy(opts, (jwt_payload, done) => {
        User.getUserById(jwt_payload._id, (err, user) => {
            if (err) {
                return done(err, false);
                console.log(err);
            }

            if (user) {
                return done(null, user);
            } else {
                return done(null, false);
            }
        });
    }));
}

is this line the problem? opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken(); I have also tried with ExtractJwt.fromAuthHeaderWithScheme("jwt") instead, but same result.

Here is my Authenticate code (which i guess woks since i get back a token on login with correct user/pass)

// Authenticate
router.post('/authenticate', (req, res, next) => {
    const username = req.body.username;
    const password = req.body.password;

    User.getUserByUsername(username, (err, user) => {
        if (err) throw err;
        if (!user) {
            return res.json({ success: false, msg: 'User not found' });
        }

        User.comparePassword(password, user.password, (err, isMatch) => {
            if (err) throw err;
            if (isMatch) {
                const token = jwt.sign({data: user}, config.secret, {
                    expiresIn: 604800 // 1 week
                });

                res.json({
                    success: true,
                    token: 'JWT ' + token,
                    user: {
                        id: user._id,
                        name: user.name,
                        username: user.username,
                        email: user.email
                    }
                });
            } else {
                return res.json({ success: false, msg: 'Wrong password' });
            }
        });
    });
});

Could also be that I'm doing something wrong in post man when making the GET request? enter image description here

1

1 Answers

0
votes

I really wanted this to work, but it seems that the new version of passport and passport-jwt have poor documentation, and is very difficult to debug....

I uninstalled both modules and installed express-jwt instead which by default requires a token for all routes. To allow my login and register routes i simply had to use one line of configuration.

const expressJWT = require('express-jwt')
.
.
.
app.use(expressJWT({secret: secret}).unless({path : ['/api/authenticate', '/api/register']}))

I can recommend this solution for securing routes in the sense that it is very easy to setup and use. I have no knowledge however about how secure it is compared to passport.