Create and consume a token using simple-jwt and PassportJS in ExpressJS
In your config.js
module.exports = {
secret: 'YOUR_SECRET'
}
Simple token creator
const jwt = require('jwt-simple');
const User = require('path');
const config = requer('path');
function tokenForUser(user){
const timestamp = new Date().getTime();
return jwt.encode({
sub: user.id, //sub: subject in jwt standard
iat: timestamp //iat: issued at time jwt standard
}, config.secret);
}
Passport JS configuration:
const passport = require('passport');
const User = require('path');
const config = require('path');
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
// Setup options for JWT Strategy
const jwtOptions = {
jwtFromRequest: ExtractJwt.fromHeader('authorization'), // Check auth header
secretOrKey: config.secret // decode with secret
};
// Create JWT Strategy
const jwtLogin = new JwtStrategy(jwtOptions, function(payload, done){
// payload: decoded token
// See if the user id in the payload exists in our db
// If it does, call 'done' with that other
// else, call done without a user object
User.findById(payload.sub, function(err, user){
if(err){return done(err, false);}
if(user){
done(null, user);
}
else{
done(null, false);
}
});
});
// Tell passport to use this strategy
passport.use(jwtLogin);
Use strategy in your controller:
const passport = require('passport');
const requireAuth = passport.authenticate('jwt', { session: false } // do not create session
...
app.get('/', requireAuth, function(req, res){
res.send({ hi: 'there' });
});
...
Add Compare Passwords method to your Mongoose object schema
Example Gist
userSchema.methods.comparePassword = function(candidatePassword, callback){
bcrypt.compare(candidatePassword, this.password, function(err, isMatch){
if(err) { return callback(err) }
callback(null, isMatch);
}
}
Add local strategy to passport config
const LocalStrategy = require('passport-local');
//Create local strategy
const localOptions = { usernameField: 'email'}; //in sign in request model, username field is: "email"
const localLogin = new LocalStrategy(localOptions, function(email, passport, done){
// Verify this username and password, call done with the user
// if it is the correct username and password,
// call done
// else call done with false
User.findOne({email: email}, function(err,user) {
if(err) { return done(err); }
if(!user) { return done(null, false); }
// compare passwords
user.comparePassword(password, function(err, isMatch){
if(err) { return done(err); }
if(!isMatch) { return done(null,false);}
return done(null, user);
}
});
});
passport.use(localLogin);
Use it in your signin endpoint:
const requireSignin = passport.authenticate('local', {session: false});
...
app.post('/signin', requireSignin, function(req, res, next){
// User had already had their email and passowrd auth'd
// We just need to give them a token
res.send({ token: tokenForUser(req.user)};
});
Good to go!