Another package we’re going to need is passport. Passport is an awesome tool to handle authentication. It can handle tons of authentication methods an in particular, we’re going to pair it with passport-local, to handle authentication ourselves without relying on 3rd part sites.

Install them:

npm install passport passport-local

Import those libraries like this:

const passport = require('passport')
const LocalStrategy = require('passport-local').Strategy

Now let’s instruct Passport to use the LocalStrategy strategy to handle logins. What we add now will be used whenever we want to log in users to our system (something we’ll do very soon).

We pass an object of options, which we need because we don’t have a username field, but we use email instead, and we tell Passport to use that as the username (as it expects a username).

Next, we add a callback function, which will be called when Passport has detected the 2 fields are present in the request.

Then, we add some logic to check if the email and password are both there (might be redundant, but..), we check if we have a user in the database with that email, using User.findOne(), a function provided by Sequelize.

If not, we call the done() function passing an error message.

Same thing if the password is not valid (something we check with the isPasswordValid() function we added in the last lesson).

Finally, if the user is found, and the password is valid, we call done() passing the user object. Passport will know what to do next.

passport.use(new LocalStrategy({
	usernameField: 'email',
  passwordField: 'password'
}, async function (email, password, done) {
	if (!email || !password ) {
		done('Email and password required', null)
		return
	}

	const user = await User.findOne({ where: {email: email}})

	if (!user) {
		done('User not found', null)
		return
	}

	const valid = await user.isPasswordValid(password)

	if (!valid) {
		done('Email and password do not match', null)
		return
	}

	done(null, user)
}))

We also need to call 2 methods here: serializeUser and deserializeUser, passing in a function for each of them, to instruct Passport what is the data we want to send to the client, and how to retrieve our users from the database, given the user information:

passport.serializeUser((user, done) => {
	done(null, user.email)
})

passport.deserializeUser((email, done) => {
	User.findOne({ where: {email: email}}).then(user => {
		done(null, user)
	})
})

Now we need to add the Passport middleware to Express, adding those 2 function calls:

  • passport.initialize() to initialize Passport
  • passport.session() to handle login sessions

as middleware.

We add this after the call to express-sessions:

server.use(
	session({
		secret: '343ji43j4n3jn4jk3n', //enter a random string here
		resave: false,
		saveUninitialized: true,
		name: 'nextbnb',
		cookie: {
			secure: false, //CRITICAL on localhost
			maxAge: 30 * 24 * 60 * 60 * 1000 //30 days
		},
		store: sessionStore
	}),
	passport.initialize(),
	passport.session()
)

Go to the next lesson