Basic User Authentication in Express
using passport local strategy (email + password)
This is Part 4 of multi-part series on ExpressJS.
You can find Part 1 here. It talks about building a basic express api and setting up mocha for testing.
You can find Part 2 here. It talks about setting up PostgreSQL, sequelize for connecting express api with databases.
You can find Part 3 here. It talks about setting up associations (has many as well as belongs to) between two models.
You know the drill by now, to the tests!
Add a test for POST /login route
Let’s add a test to make sure users can find the login route and our api is able to find them and log them in.
touch test/auth.spec.js
We send user email and password to POST /login
route and expect response code to be 200.
Simple enough.
Update factory
We need to update user factory and also the helper we have set up at the start of the test.
We add email
and encryptedPassword
fields to our user factory.
Update helper
We should update the way we create our user, because now using a specific email is important to us in our tests.
Before we move forward, clear the seeds.
Set up Clear seeds functionality
Update package.json
scripts and add two scripts instead of seed
command we had earlier:
“seed:create”: “node ./src/app.js create”,
will create seeds
“seed:clean”: “node ./src/app.js clean”,
will clean our database
Update our seeds file with clean seeds function
in deleteSeeds
method, we destroy all instances of User and Post.
Finally, we hook it up in our app.js
We require the method from seeders and set up conditionals to execute create or destroy seeds functionality as expected.
run npm run seed:clean
and check http:localhost:3000/posts
by running npm run start
and you should get an empty array.
This is good.
Time to code and get the tests to go green!
Setting up Passport and Passport-local
Install passport and passport-local
npm i passport passport-local
create auth folder and index.js to hold our login logic, use passport local strategy to resolve login logic.
To summarize the code —
- We set up a
POST /login
route using router. - We call in
passport.authenticate
command, and inform passport that we want it to uselocal
strategy. - We define local strategy by
passport.use
and create anew LocalStrategy
, where we find a user that hasemail
from our incoming request. - If we indeed have such a user, we confirm the
encryptedPassword
is valid by usingvalidatePassword
method we added to User model. - Once the authentication is confirmed, we return User object using the
Done
. Else we just sendfalse
.
The user object is now attached to request as req.user
.
Of course, all the code above is for naught, if we don’t actually use it.
We update our app.js
like thus —
Just import the file const auth = require(‘./auth’)
and use it like app.use(auth)
.
Time to actually add email and encryptedPassword columns to our User model.
Add email and encrypted password as columns for user model
First step — generate a migration.
Next up — Update our migration file to add two columns to our User model.
Next — Run the migration by sequelize db:migrate
to update our database table.
Before we update our User model with email
and encryptedPassword
columns, we shall set up a package which helps us to actually encrypt the incoming password.
Use bcryptjs
to encrypt and save password —
npm install bcryptjs
Now we update our User model —
A few interesting things are happening here —
- At the top, we added email and password field and also added some validations
email: { type: DataTypes.STRING, isEmail: true, unique: true, allowNull: false, }
encryptedPassword: { type: DataTypes.STRING, allowNull: false, }
- Then we add a
beforeCreate
action, where we encrypt the incoming password. This is used when we create a new user - We also define
validatePassword
where bcrypt just does all the hard work of comparing our stored password ( which is encrypted) and the incoming password, and let’s us know if both the passwords match or not - Finally we have
cryptPassword
function, which actually handles encryption. It generates salt and hashes the plain-text password.
What we did till now
- Create and use a
POST /login
route - Set up Passport local strategy and verify incoming email and password. Send appropriate response. After succesful authentication,
req.user
is available. - Update User model and create migration to update db tables.
This is everything we have to do in order for the tests to go green!
But wait!
Even though the login is successful, how will our API remember a user when he makes another network request?
That is a valid question, and has many solutions.
We will look at one of them, the Passport-JWT, in the next article.
Here is Part 5.
Craft Academy is a Tech Education Provider that aims to bring new talent to the market and help to solve the shortage of tech workers. We are founded on the belief that modern development standards, agile methodologies, and business skills are fundamental for IT professionals.
Our primary service is a 12-week coding bootcamp designed to provide individuals with a foundation of skills that allows them to enter the industry as junior developers.
With that foundation, our learners find employment in various industries or start their own businesses that bring new innovations to the market.
Would you like to know more about what we do? Follow us here on Medium, Facebook, Twitter or visit our website.