Node JS Authentications with passport-jwt unauthorized

393 views Asked by At

Im trying to setup my Node JS API.

I have a User model :

// Dependencies
var restful = require('node-restful');
var mongoose = restful.mongoose;

var bcrypt = require('bcrypt');

// Schema
var userSchema = new mongoose.Schema({
    username: {
        type: String, 
        required: true, 
        unique: true},
    firstname: {
        type: String, 
        required: true
    },
    lastname: {
        type: String, 
        required: true
    },
    email: {
        type: String, 
        required: true, 
        unique: true,
        lowercase: true
    },
    password: {
        type: String, 
        required: true},
},
{
    timestamps: true
});

// Saves the user's password hashed
userSchema.pre('save', function (next) {  
  var user = this;
  if (this.isModified('password') || this.isNew) {
    bcrypt.genSalt(10, function (err, salt) {
      if (err) {
        return next(err);
      }
      bcrypt.hash(user.password, salt, function(err, hash) {
        if (err) {
          return next(err);
        }
        user.password = hash;
        next();
      });
    });
  } else {
    return next();
  }
});


// Use bcrypt to compare passwords
userSchema.methods.comparePassword = function(pw, cb) {  
  bcrypt.compare(pw, this.password, function(err, isMatch) {
    if (err) {
      return cb(err);
    }
    cb(null, isMatch);
  });
};

module.exports = restful.model('Users', userSchema);

I want to use passport with jwt for authentication :

// Dependencies
var JwtStrategy = require('passport-jwt').Strategy;
var ExtractJwt = require('passport-jwt').ExtractJwt;
var config = require('../config/database');

// Load models
var User = require('../models/user');

// Logique d'authentification JWT
module.exports = function(passport) {  
  var opts = {};
  opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme('JWT');
  opts.secretOrKey = config.secret;
  opts.audience = 'localhost';

  passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
    User.findById(jwt_payload._id, function(err, user) {
      if (err) {
        return done(err, false);
      }
      if (user) {
        done(null, user);
      } else {
        done(null, false);
      }
    });
  }));
  passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
    Company.findById(jwt_payload._id, function(err, company) {
      if (err) {
        return done(err, false);
      }
      if (company) {
        done(null, company);
      } else {
        done(null, false)
      }
    });
  }));
};

And my route for authentication :

// User
router.post('/users/login', (req, res) => {
    User.findOne({
        email: req.body.email
    }, (err, user) => {
        if (err) throw err;

        if (!user) {
            res.json({success: false, message: 'Authentication failed. User not found.'});
        } else {
            // Check if passwords matches
            user.comparePassword(req.body.password, (err, isMatch) => {
                if (isMatch && !err) {
                    // Create token if the password matched and no error was thrown
                    var token = jwt.sign(user, config.secret, {
                        expiresIn: 10080 // in seconds
                      });
                    res.json({success: true, token: 'JWT ' + token, user: {
                        id: user._id,
                        username: user.username,
                        email: user.email
                    }});    
                } else {
                    res.json({success: false, message: 'Authentication failed. Passwords did not match.'});
                }
            });
        }
    });
});

Everything work great on postman. The token is correctly generated and signed with user's informations.

But i have a problem with the authentication on a protected route :

router.get('/users/profile', passport.authenticate('jwt', { session: false }), function(req, res) {  
    res.send('It worked! User id is: ' + req.user._id + '.');
  });

Everytime, it gives me an "Unauthorized 401" Error.

I really dont know where is the problem, i think the problem is around jwtFromRequest, i also tried with Bearer but it also doesn't work...

1

There are 1 answers

0
David On

I think a good option to avoid this kind of problems is to start from a base project that uses this authentication strategy, and after you have that working, modify it with your functionality.

Here you have an example with jwt authentication strategy and Refresh token implementation: https://solidgeargroup.com/refresh-token-autenticacion-jwt-implementacion-nodejs?lang=es