Struggle with passport and jwt — by Steven Lacerda (Morgan Hill, CA)

Steven Lacerda
3 min readOct 21, 2018

--

I was having a heck of a time with passport and jwt. So, here’s what I realized that I needed to do in order to get req.user in my routes. Of course, I knew that I needed a middleware, but what???

// middleware to test user authentication and set in req.user
function verifyUser(req, res, next) {
passport.authenticate('jwt', { session: false }, (err, user, info) => {
if (err || !user) {
return res.status(400).json({
message: info.message
});
}
req.user = user;
next()
})(req, res, next);
}

And then in my routes:

app.use("/api/invoices", verifyUser, invoices);

Just to cover all the bases here, my passport config file looks like:

const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const mongoose = require('mongoose');
const User = require('../models/User');
const keys = require('../config/keys');
const options = {};
options.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
options.secretOrKey = keys.secretOrKey;
module.exports = passport => {
passport.use(new JwtStrategy(options, (payload, done) => {
User.findById(payload.id)
.then(user => {
if (user) {
return done(null, user);
} else {
return done(null, false);
}
})
.catch(err => console.log(err))
}));
};

and my server.js file:

const mongoose = require('mongoose');
const express = require("express");
const app = express();
const path = require('path');
const morgan = require('morgan');
const db = require('./config/keys').mongoURI;
mongoose
.connect(db, { useNewUrlParser: true })
.then(() => console.log("Connected to MongoDB successfully"))
.catch(err => console.log(err));
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// setup logger
app.use(morgan('dev'));
const passport = require('passport');
app.use(passport.initialize());
require('./config/passport')(passport);
// setup static folder for frontend
app.use(express.static( `${__dirname}/frontend/build`));
// router routes
const users = require("./routes/api/users");
const invoices = require("./routes/api/invoices");
const clients = require("./routes/api/clients");
const subs = require("./routes/api/subscriptions");
// middleware to test user authentication and attach user as req.user
function verifyUser(req, res, next) {
passport.authenticate('jwt', { session: false }, (err, user, info) => {
if (err || !user) {
return res.status(400).json({
message: info.message
});
}
req.user = user;
next()
})(req, res, next);
}
app.get("/", (req, res) => res.send(""));
app.use("/api/users", users);
app.use("/api/invoices", verifyUser, invoices);
app.use("/api/clients", verifyUser, clients);
app.use("/api/subscriptions", verifyUser, subs);
// serve up index.html for frontend
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, '/frontend/build/index.html'));
});
const port = process.env.PORT || 5000;app.listen(port, () => console.log(`Server is running on port ${port}`));

And my login and register routes:

const express = require("express");
const router = express.Router();
const bcrypt = require('bcryptjs');
const User = require('../../models/User');
const jwt = require('jsonwebtoken');
const keys = require('../../config/keys');
const passport = require('passport');
const validateRegisterInput = require('../../validation/register');
const validateLoginInput = require('../../validation/login');
router.post('/register', (req, res) => {
const { errors, isValid } = validateRegisterInput(req.body);
if (!isValid) {
return res.status(400).json(errors);
}
User.findOne({ email: req.body.email })
.then(user => {
if (user) {
// errors.name = "User already exists";
return res.status(400).json({ email: "A user has already registered with this address"})
} else {
const newUser = new User(req.body);
// don't store plaintext password
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) throw err;
newUser.password = hash;
newUser
.save()
.then(user => {
const payload = { id: user.id, name: user.name };
jwt.sign(payload, keys.secretOrKey, { expiresIn: 86400 * 7 }, (err, token) => {
res.json({
success: true,
token: "Bearer " + token
});
});
})
.catch(err => console.log(err));
});
});
}
});
})
router.post('/login', (req, res) => {
const { errors, isValid } = validateLoginInput(req.body);
if (!isValid) {
return res.status(400).json(errors);
}
const email = req.body.email;
const password = req.body.password;
User.findOne({email})
.then(user => {
if (!user) {
errors.name = "This user does not exist";
return res.status(404).json({email: 'This user does not exist'})
}
bcrypt.compare(password, user.password)
.then(isMatch => {
if (isMatch) {
const payload = { id: user.id, name: user.name };
jwt.sign(payload, keys.secretOrKey, {expiresIn: 3600 }, (err, token) => {
res.json({
success: true,
token: 'Bearer ' + token
});
});
} else {
errors.password = "Incorrect password";
return res.status(400).json({password: 'Incorrect password'});
}
})
})
})

Solving a problem is as good as those sexual feelings…sometimes, okay, maybe not. Straight from Morgan Hill, CA. Good luck!

by Steven Lacerda

--

--

Steven Lacerda
Steven Lacerda

Written by Steven Lacerda

Steve Lacerda is a software engineer specializing in web development. His favorite 80’s song is Let’s Put the X in Sex by Kiss.

No responses yet