User Authentication
This walkthrough presumes that your project is bundled, with es6 module support.
#
WhyIn many applications, you'll need to have authentication to handle user logins and permissions. Not only will you need to add functionality for user authentication, you'll also need functionality that ensures security clouding sensitive user information. There are several authentication philosophies, but we`ll focus on bcrypt, web token authentication, and passport.
Interested in encryption/decryption? Read this article for an opinionated briefing on bcrypt.
#
WhatSimply put, bcrypt is “a library to help you hash passwords.” Bcrypt gives you the ability to hash and salt (dealing with encryption) passwords before storing in a database or passing across a network.
Jsonwebtoken is a standard method for creating data with a secret/private key that offers encryption for JSON payloads that detail permissions, roles, etc from the server for user access on the client-side. The tokens are signed either using a private secret or a public/private key.
Passport offers strategies (plugins) to authenticate requests to our server. We`ll specifically be using the http-bearer and local plugin strategies.
#
HowTo begin, let`s install the npm packages for:
- Bcrypt
- Jsonwebtoken
- Passport
- Passport-local
- Passport-http-bearer
#
Middleware SubfolderWe will start by creating a new subfolder named middleware
inside of our server
directory:
Create two new files: bearerstrategy.js
and localstrategy.js
inside of middleware.
#
BearerStrategyInside of bearerstrategy.js
, import passport
and passport-http-bearer:
Also import your index.js from “../db/models”, and your ValidToken
function from “../utils/security/tokens” (both to be created later):
Next, we will create and implement a passport middleware using passport-http-bearer to authenticate access tokens:
We will use this middleware logic and BearerStrategy to intercept incoming http requests and validate the attached access tokens with results in our database. Shortly, we will create our ValidToken
and db
functions.
#
LocalStrategyInside of localstrategy.js, import passport
and passport-local
:
Also import your index.js from “../db/models”, and your comparePassword
function from “../utils/security/tokens” (both to be created later):
This middleware logic with passport allows us serialize and deserialize users, and compare the password entered with the correct password in the database.
#
DB QueriesNow let's work in two new files under our "../db/queries" named tokens.js
and users.js
Before we begin with the query methods for finding users and tokens, let`s make sure we have a table in our database to hold these values.
In MySQL workbench, create a new table accesstokens
with the following structure:
Also, create or alter a users
table to have, at least, the following fields for id, email and password:
NOTE: You should not, and we will not store raw passwords in our or any database. We will store encrypted passwords/information.
#
Token QueriesInside a new file named tokens.js
, import our Query function from “./db/model”
Next, we`ll write three functions for finding, inserting and updating access tokens in our database:
#
User QueriesInside a new file named users.js
, import our Query function from “./db/model” like before.
Next, we`ll write three functions for finding by id, finding by email and creating new users in our database:
#
Utility FilesCreate a subfolder named utils
inside of your server
folder, and add the following:
In our “utils/security” folder, we`ll use the bcrypt module to encrypt and decrypt passwords and other information.
#
Utils: PasswordsInside of passwords.js
, import bcrypt
.
Next, we`ll write two functions for hashing and comparing passwords for encryption and authentication:
#
Utils: TokensInside of tokens.js
, import crypto (from bcrypt), jsonwebtoken, and “db/models”
. If you have a config file with environment variables, or a types file with defined typings, import them as well.
Next, we`ll write two functions for creating and validating access tokens for authentication:
#
RoutesNow we will implement our passport and bcrypt middlewares in our routes.
#
Server.jsIn your server.js
file, we will create our express server, initialize passport, parse request bodies, enable cors, create routing, and handle errors:
#
Routes/index.jsIn your routes
folder, create an index.js
file. Import authRouter
, apiRouter
, and express
to create your routes:
#
Routes/api/index.jsIn your routes
folder, create a subfolder called api
with an index.js
file. Import passport
and express
:
#
Routes/auth/index.jsLet's consider having a login page on our client-side where users can log in to your application if they have an account, or sign up if they need to create an account. We`ll need to have api routes that authenticate user registering or logging in.
Create a subfolder named auth
that contains an index.js, login.js,
and register.js
file:
In your routes/auth/login.js
file, import express
, and two route files that we will need to create for login and registration routes:
In your routes/auth/login.js
file, import express
, passport
, and the CreateToken
function we created in our utils/security/tokens.js
file:
Initialize an express router, and create an endpoint for a post
request at “/login”. We'll use passport.authenticate("local")
to authenticate incoming requests before our request handler is used. Inside of our request handler, invoke CreateToken
and pass in the user id from the request body. Once the token is created, send the token, user id, and user role back to the client-side in the response body. Our route should resemble the following:
In your routes/auth/register.js
file, import express
, our insert user db function, hashPassword
function, and the CreateToken
function to use for creating new users:
Initialize an express router, and create an endpoint for a post
request at “/register”. Inside of our request handler, invoke hashPassword
and pass in the inputted password from the request body. Once the password is encrypted, reassign the password on the user to the encrypted result, and insert the user into the database. Then use CreateToken
to create an access token for the new user, and send the token, user id, and user role back to the client-side as the response body. Our route should resemble the following:
Alright! Now we have routes that authenticate user logins and registers new users. Next step would be to create the frontend!