Authentication Quickstart with Express, Passport and Sequelize
I have created an authentication quick-start that demonstrates the use of authentication middleware Passport. Passport is a drop-in middleware for Express-based web applications that allows you to use many provided authentication strategies or create your own. In this demo I implemented a local strategy where all data are stored in a SQL database. Sequelize is a popular ORM library for Node.js and I used it here to query and change the data.
The quick-start is a web application utilizing mentioned libraries to provide basic UI for log-in, log-out and sign-up pages. I also added basic end-to-end tests written in Nightwatch.js. Everything is available on GitHub in auth-quickstart repository. To start, clone the repository:
git clone https://github.com/stribny/auth-quickstart.git
You can find information about the requirements, installation, configuration and how to run the application in the README file. Here I’d like to go over some of the code to help you understand it a little bit more.
Using Sequelize
First it is necessary to initialize Sequelize with connection information. I do that by providing a connection string in app/sequelize.js (the example uses PostgreSQL):
// app/sequelize.js
var Sequelize = require('sequelize'),
sequelize = new Sequelize('postgres://postgres:postgres@localhost:5432/example')
module.exports = sequelize
The model of the application is very simple. I decided to create a separate configuration file for each entity (e.g. User) and one configuration file to define the relationship between them. You can see basic definition of User in app/model/User.js. It includes the database mapping for some basic attributes and constrains:
// app/model/User.js
var Sequelize = require('sequelize')
var attributes = {
username: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
validate: {
is: /^[a-z0-9\_\-]+$/i,
}
},
email: {
type: Sequelize.STRING,
validate: {
isEmail: true
}
},
firstName: {
type: Sequelize.STRING,
},
lastName: {
type: Sequelize.STRING,
},
password: {
type: Sequelize.STRING,
},
salt: {
type: Sequelize.STRING
}
}
var options = {
freezeTableName: true
}
module.exports.attributes = attributes
module.exports.options = options
This is later utilized in app/model/models.js, where we tell Sequelize to use our entity configurations and optionally define any relationships between them. This is a good approach because it keeps our configuration files small and well structured. Since I used only User entity in this example, no relationships are defined so far.
// app/model/models.js
var UserMeta = require('./User.js'),
connection = require('../sequelize.js')
var User = connection.define('users', UserMeta.attributes, UserMeta.options)
// you can define relationships here
module.exports.User = User
And that’s all! Our simple database mapping is ready to be used and our models are exported and available from this module by their names. Now whenever we need to work with the model, we can just use it like this:
var Model = require('path/to/model/models.js')
Model.User.*
Using Passport
To be able to use local authentication strategy, we have to write the logic that queries the database and checks that provided username and password are correct. I put the strategy definition to app/setupPassport.js. You can see that it is just a matter of getting a User instance from the database based on the username and then checking that password hash matches the one provided.
// app/setupPassport.js
passport.use(new LocalStrategy(
function(username, password, done) {
Model.User.findOne({
where: {
'username': username
}
}).then(function (user) {
if (user == null) {
return done(null, false, { message: 'Incorrect credentials.' })
}
var hashedPassword = bcrypt.hashSync(password, user.salt)
if (user.password === hashedPassword) {
return done(null, user)
}
return done(null, false, { message: 'Incorrect credentials.' })
})
}
))
Passport also requires that we implement serializeUser()
and deserializeUser()
functions. You can see them in the same file. For this implementation I just modified examples from the official documentation so that they use the Sequelize model. Other necessary configuration is well described in the Configuration section (covered in app.js file). When Passport is properly configured as a middleware, we can use it to define auth-related routes or protect routes from being accessed, see app/routers/appRouter.js.
The quick-start is quite feature complete, so you can also see how forms are defined and handled, how Handlebars can be used within Express application, how to use connect-flash
to flash error messages and so on. The whole example is fairly simple, so it should be easy to follow once you get a little bit familiar with Express, Passport and Sequelize.
Last updated on 29.9.2015.