Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

André Aguiar
André Aguiar
11,620 Points

MongoStore logout error

Hello! Thanks for the excellent course so far, I'm learning a lot.

I'm facing a problem related to the "/logout" router. After installing "connect-mongo" I'm able to log in, and it creates a collection in the DB correctly, but I'm unable to log out using "req.session.destroy(...)". When I try, I receive the following error: "Cannot convert undefined or null to object".

If I remove the connection between the MongoStore and the mongooseConnection, the code works again, but without register the sessions in the database.

app.js

var express = require('express')
var bodyParser = require('body-parser')
const mongoose = require('mongoose')
const session = require('express-session')
const MongoStore = require('connect-mongo')(session)
var app = express()

// mongodb connection
mongoose.connect('mongodb://localhost:27017/bookworm')
const db = mongoose.connection

// mongo Error
db.on('error', console.error.bind(console, 'connection error:'))

// use sessions for tracking logins
app.use(session({
  secret: 'treehouse loves you',
  resave: true,
  saveUninitialized: false,
  store: new MongoStore({
    mongooseConnection: db
  })
}))

// make userId available in templates
app.use((req, res, next) => {
  res.locals.currentUser = req.session.userId
  next()
})

// parse incoming requests
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))

// serve static files from /public
app.use('/static', express.static('public'))
// app.use(express.static(__dirname + '/public'))

// view engine setup
app.set('view engine', 'pug')
// app.set('views', __dirname + '/views')

// include routes
var routes = require('./routes/index')
app.use('/', routes)

// catch 404 and forward to error handler
app.use(function (req, res, next) {
  var err = new Error('File Not Found')
  err.status = 404
  next(err)
})

// error handler
// define as the last app.use callback
app.use(function (err, req, res, next) {
  res.status(err.status || 500)
  res.render('error', {
    message: err.message,
    error: {}
  })
})

// listen on port 3000
app.listen(3000, function () {
  console.log('Express app listening on port 3000')
})

router - index.js

var express = require('express')
var router = express.Router()
const User = require('../models/user')
const mid = require('../middleware')

// GET /profile
router.get('/profile', mid.requiresLogin, (req, res, next) => {
  User.findById(req.session.userId)
    .exec(function (error, user) {
      if (error) {
        return next(error)
      } else {
        return res.render('profile', {title: 'Profile', name: user.name, favorite: user.favoriteBook})
      }
    })
})

// GET /logout
router.get('/logout', (req, res, next) => {
  if (req.session) {
    // delete session object
    req.session.destroy(function (err) {
      if (err) {
        return next(err)
      } else {
        return res.redirect('/')
      }
    })
  }
})

// GET /login
router.get('/login', mid.loggedOut, (req, res, next) => {
  return res.render('login', {title: 'Log In'})
})

// POST /login
router.post('/login', (req, res, next) => {
  if (req.body.email && req.body.password) {
    User.authenticate(req.body.email, req.body.password, function (error, user) {
      if (error || !user) {
        const err = new Error('Wrong email or password.')
        err.status = 401
        return next(err)
      } else {
        req.session.userId = user._id
        return res.redirect('/profile')
      }
    })
  } else {
    const err = new Error('Email and password are required')
    err.status = 401
    return next(err)
  }
})

// GET /register
router.get('/register', mid.loggedOut, (req, res, next) => {
  return res.render('register', {title: 'Sign Up'})
})

// POST /register
router.post('/register', (req, res, next) => {
  if (req.body.email &&
    req.body.name &&
    req.body.favoriteBook &&
    req.body.password &&
    req.body.confirmPassword) {
    // confirm that user typed same password twice
    if (req.body.password !== req.body.confirmPassword) {
      const err = new Error('Passwords do not match.')
      err.status = 400
      return next(err)
    }

    // create object with form input
    const userData = {
      email: req.body.email,
      name: req.body.name,
      favoriteBook: req.body.favoriteBook,
      password: req.body.password
    }

    // use schema's 'create' method to insert document into Mongo
    User.create(userData, (error, user) => {
      if (error) {
        return next(error)
      } else {
        req.session.userId = user._id
        return res.redirect('/profile')
      }
    })
  } else {
    const err = new Error('All fields required.')
    err.status = 400
    return next(err)
  }
})

// GET /
router.get('/', function (req, res, next) {
  return res.render('index', { title: 'Home' })
})

// GET /about
router.get('/about', function (req, res, next) {
  return res.render('about', { title: 'About' })
})

// GET /contact
router.get('/contact', function (req, res, next) {
  return res.render('contact', { title: 'Contact' })
})

module.exports = router

package.json

{
  "name": "treehouse-express-auth",
  "version": "1.0.0",
  "description": "A project for learning how to add authentication to a web application.",
  "author": "Treehouse Island, Inc.",
  "private": true,
  "scripts": {
    "start": "node ./app"
  },
  "dependencies": {
    "bcrypt": "^1.0.3",
    "body-parser": "^1.13.3",
    "connect-mongo": "^2.0.0",
    "express": "^4.13.4",
    "express-session": "^1.15.6",
    "mongoose": "^5.0.0-rc1",
    "pug": "^2.0.0-beta2"
  },
  "license": "MIT"
}

Thank you!

1 Answer

Neil McPartlin
Neil McPartlin
14,662 Points

Hi Andre,

I just completed this course myself a few weeks back. Logout works fine so I switched my 2 files with yours (routes/index.js & app.js) and logout still works.

I see you have coded with fat arrow functions and I'd assume your browser version is uptodate as your login works, so I doubt that's the issue. I saw you were using a newer version of Mongoose so I updated mine too. Logout still works.

I assume the error you see is being shown in your browser devtools Javascript console. The only new error I see there is that the style.css is not being found and I see you are experimenting with the 'serve static files from' entry in app.js.

From what you wrote, you can see post login, that the session entry actually appears in MongoDB so it does seem odd that the new /logout entry is not working for you.

I think our node_modules entries are the same but perhaps there is an error hidden in middleware/index.js and/or models/user.js. Good luck.