Search code examples
node.jsexpresspassport.jspassport-localpassport-local-mongoose

How to automatically log in dev user after Node/Express server restart using Passport


I'm working on a personal project with Node/Express, and I'm sure you understand that it's annoying to have to log back in every time I restart the server after making a change.

I'm using passport-local-mongoose for authentication, and all of that works fine. I'm just looking for a way to have the startup process include automatically logging in a user 'bob' who has an admin role so I can just try out the routes I'm working on without having to log back in every 5 minutes.

I've tried this:


//set local variables middleware
app.use(function (req,res,next) {
    // req.user = {
    //  '_id':'6011d61a04abe04708edfb5f',
    //  'username':'bob'
    // }
    // req.user = User.findOne({username: 'bob'});
    req.user = User.authenticate()('bob','password');
    console.log(req.user);
    res.locals.currentUser = req.user;
    //set success flash message
    res.locals.success = req.session.success || "";
    //delete flash message after sending it to the page so it doesn't show again
    delete req.session.success;
    //set error flash message
    res.locals.error = req.session.error || "";
    //delete flash message after sending it to the page so it doesn't show again
    delete req.session.error;
    //continue on to the next function in the middlware/route chain
    next();
})

(Note that I've tried 3 different ways of assigning the user to req.user) and I've placed it immediately after the app.use(passport.session()) and a few other places in my app.js file, and it seems to completely ignore the entire app.use function. That console.log doesn't run, and I can't access currentUser in any routes.

Just for giggles, here's my entire app.js:

var createError = require('http-errors');
var express = require('express');
const bodyParser = require('body-parser');
var path = require('path');
const jwt = require('jsonwebtoken');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
const mongoose = require('mongoose');
const User = require('./models/user');
const passport = require('passport');

// CHANGE: USE "createStrategy" INSTEAD OF "authenticate"
passport.use(User.createStrategy());
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());

require('mongoose-type-url');



var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var booksRouter = require('./routes/books');

const app = express();

//connect to database
mongoose.connect(process.env.DATABASE_URL,{
    useNewUrlParser:true, 
    useUnifiedTopology:true,
  useFindAndModify: false,
  useCreateIndex:true
}).then(() => {
    console.log('Connected to Mongo DB');
}).catch(err => {
    console.log('Mongoose error: ',err);
});

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(require('express-session')({
  secret:"more things in the world",
  resave: false,
  saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static(path.join(__dirname, 'public')));


//set local variables middleware
app.use(function (req,res,next) {
    // req.user = {
    //  '_id':'6011d61a04abe04708edfb5f',
    //  'username':'bob'
  // }
  // req.user = User.findOne({username: 'bob'});
  req.user = User.authenticate()('bob','password');
  console.log(req.user);
    res.locals.currentUser = req.user;
    //set success flash message
    res.locals.success = req.session.success || "";
    //delete flash message after sending it to the page so it doesn't show again
    delete req.session.success;
    //set error flash message
    res.locals.error = req.session.error || "";
    //delete flash message after sending it to the page so it doesn't show again
    delete req.session.error;
    //continue on to the next function in the middlware/route chain
    next();
})

app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/books', booksRouter);


if (app.get('env') == 'development'){ 
  require('dotenv').config(); 
};

app.use(async (req, res, next) => {
  if (req.headers["x-access-token"]) {
    const accessToken = req.headers["x-access-token"];
    const { userId, exp } = await jwt.verify(accessToken, process.env.JWT_SECRET);
    // Check if token has expired
    if (exp < Date.now().valueOf() / 1000) { 
    return res.status(401).json({ error: "JWT token has expired, please login to obtain a new one" });
    } 
    res.locals.loggedInUser = await User.findById(userId); next(); 
  } else { 
    next(); 
  } 
 });

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});


let port = process.env.PORT;
if (port == null || port == "") {
  port = 8080;
}
app.listen(port, () => {
    console.log("server has started, listening on port "+port);
});

module.exports = app;

EDIT: Disclaimer: I added that last User.authenticate attempt while posting this, and assumed it wouldn't work, because it hadn't worked elsewhere in the file. But apparently it's now working? However the issue with not being able to access the currentUser in other routes is still there, but I can at least work with this.


Solution

  • It turns out that I forgot that app.use is MIDDLEWARE (it even has it in the comment from when I used this in an old project from class). It doesn't run until a route (any route) is actually called. It doesn't run at server startup like I originally thought when posting this.

    Therefore, I was able to access req.user just fine in the route that I needed it. the res.locals.currentUser still wasn't available, but I'll take this for the time being.