Node.js Authentication using Passport.js

A lifelong learner. Love to travel. Listen to music.
Search for a command to run...

A lifelong learner. Love to travel. Listen to music.
No comments yet. Be the first to comment.
Check out the source code here And Video *PlayList* *Representational state transfer (REST) or [RESTful](https://en.wikipedia.org/wiki/Representational_state_transfer) [Web services](https://en.wikipedia.org/wiki/Web_service) are one way of providi...
Best Practices for Path Structure, Versioning, and Error Handling

Understanding the Performance Implications of async and defer Attributes

Overview static: Default position. It does not allow setting properties like top, bottom, left, right, z-index relative: Acts the same as static. but allows positioning it relatively by putting properties like top, bottom, left, right, z-index absolu...

Overview When an element in the browser has a conflict of styles, the browser uses a set of rules to determine which style should be rendered. This set of rules is defined as CSS Selector Specificity. For instance, for an element, if we have the foll...

Master block, inline, flex, and grid to build better web layouts

Check the source code here

Authentication is an important portion for web application. From client side, like a mobile application must require a secure authentication to the server and *passport* is a prominent helper.
Here I’m developing a simple oAuth(open authentication) application and show how to secure routing.
Two routes will be available: guest, user
The /guest routes can be accessed by anyone
The /user routes can be accessed by the authenticate users
Dependency
Make your directory and inside the directory, create a file named package.json
mkdir myPassportAuthentication
cd myPassportAuthentication/
touch package.json
Paste the following code in your package.json file:
{
**"name"**: **"my-passport-authentication"**,
**"main"**: **"server.js"**,
**"dependencies" **: {
**"express"**: **"~4.14.0"**,
**"mongoose"**: **"~4.6.1"**,
**"passport"**: **"~0.3.2"**,
**"passport-local" **: **"~1.0.0"**,
**"bcrypt-nodejs" **: **"latest"**,
**"morgan"**: **"~1.7.0"**,
**"body-parser"**: **"~1.15.2"**,
**"cookie-parser"**: **"~1.4.3"**,
**"method-override"**: **"~2.3.6"**,
**"express-session"**: **"~1.14.1"
**}
}
To download the dependencies, run
npm install
So our entry point is the server.js
Server
Lets create the server.js in the same directory.
touch server.js
Now paste the following code in server.js
*// server.js
// set up ======================================================================
// get all the tools we need
***var **express = require(**'express'**);
**var **app = express();
**var **path = require(**'path'**);
**var **port = process.**env**.PORT || 8080;
**var **mongoose = require(**'mongoose'**);
**var **passport = require(**'passport'**);
**var **morgan = require(**'morgan'**);
**var **cookieParser = require(**'cookie-parser'**);
**var **bodyParser = require(**'body-parser'**);
**var **session = require(**'express-session'**);
*// router files ===============================================================
***var **authRoutes = require(**'./routes/auth'**);
**var **testRoutes = require(**'./routes/test'**);
**var **configDB = require(**'./config/database'**);
*// configuration ===============================================================
*mongoose.connect(configDB.**url**); *// connect to our database
*require(**'./config/passport'**)(passport); *// pass passport for configuration
// set up our express application
*app.use(morgan(**'dev'**)); *// log every request to the console
*app.use(cookieParser()); *// read cookies (needed for auth)
*app.use(bodyParser.**json**()); *// get information from html forms
*app.use(bodyParser.**urlencoded**({ **extended**: **true **}));
*// required for passport
*app.use(session({
**secret**: **'eminem'**, *// session secret
***resave**: **true**,
**saveUninitialized**: **true
**}));
app.use(passport.initialize());
app.use(passport.session()); *// persistent login sessions
// routes ======================================================================
*app.use(**'/auth'**, authRoutes);
app.use(**'/test'**, testRoutes);
*// launch ======================================================================
*app.listen(port);
**console**.log(**'The magic happens on port ' **+ port);
Routes
Create two routing files,
mkdir routes
cd routes
mkdir auth
mkdir test
cd auth
touch index.js
cd ..
cd test
touch index.js
From the both routing file
./routes/auth/index.js
./routes/test/index.js
Export the router module.
Paste the following code on the both file:
**var **express = require(**'express');
var **router = express.Router();
module.exports = router;
Database
Now time to configure database. Follow the following commands:
mongo
use myPassportAuth
So our database is created, now create the config file and put database info:
Go to the project root directory and
mkdir config
cd config
mkdir database
touch index.js
Inside the ./config/database/index.js paste the following code:
*// config/database.js
*module.exports = {
**'url' **: **'mongodb://localhost/myPassportAuth'
**};
Passport
Go to the root directory and follow the command:
cd config
mkdir passport
cd passport
touch index.js
Now paste the following code to the ./config/passport/index.js
*// load all the things we need
***var **LocalStrategy = require(**'passport-local'**).Strategy;
**var User **= require(**'../../models/user'**);
**var ***myLocalConfig *= (passport) => {
*// =========================================================================
// passport session setup ==================================================
// =========================================================================
// required for persistent login sessions
// passport needs ability to serialize and unserialize users out of session
// used to serialize the user for the session
*passport.serializeUser(**function**(user, done) {
done(**null**, user.**id**);
});
*// used to deserialize the user
*passport.deserializeUser(**function**(id, done) {
**User**.findById(id, **function**(err, user) {
done(err, user);
});
});
*// =========================================================================
// LOCAL LOGIN =============================================================
// =========================================================================
*passport.use(**'local-login'**, **new **LocalStrategy({
*// by default, local strategy uses username and password, we will override with email
***usernameField **: **'email'**,
**passwordField **: **'password'**,
**passReqToCallback **: **true ***// allows us to pass in the req from our route (lets us check if a user is logged in or not)
*},
**function**(req, email, password, done) {
**if **(email)
email = email.toLowerCase(); *// Use lower-case e-mails to avoid case-sensitive e-mail matching
// asynchronous
*process.nextTick(**function**() {
**User**.findOne({ **'local.email' **: email }, **function**(err, user) {
*// if there are any errors, return the error
***if **(err)
**return **done(err);
*// if no user is found, return the message
***if **(!user)
**return **done(**null**, **false**);
**if **(!user.validPassword(password))
**return **done(**null**, **false**);
*// all is well, return user
***else
return **done(**null**, user);
});
});
}));
*// =========================================================================
// LOCAL SIGNUP ============================================================
// =========================================================================
*passport.use(**'local-signup'**, **new **LocalStrategy({
*// by default, local strategy uses username and password, we will override with email
***usernameField **: **'email'**,
**passwordField **: **'password'**,
**passReqToCallback **: **true ***// allows us to pass in the req from our route (lets us check if a user is logged in or not)
*},
**function**(req, email, password, done) {
**if **(email)
email = email.toLowerCase(); *// Use lower-case e-mails to avoid case-sensitive e-mail matching
// asynchronous
*process.nextTick(**function**() {
*// if the user is not already logged in:
***if **(!req.**user**) {
**User**.findOne({ **'local.email' **: email }, **function**(err, user) {
*// if there are any errors, return the error
***if **(err)
**return **done(err);
*// check to see if theres already a user with that email
***if **(user) {
**return **done(**null**, **false**);
} **else **{
*// create the user
***var **newUser = **new User**();
newUser.local.**email **= email;
newUser.local.**password **= newUser.generateHash(password);
newUser.save(**function**(err) {
**if **(err)
**return **done(err);
**return **done(**null**, newUser);
});
}
});
*// if the user is logged in but has no local account...
*} **else if **( !req.**user**.**local**.**email **) {
*// ...presumably they're trying to connect a local account
// BUT let's check if the email used to connect a local account is being used by another user
***User**.findOne({ **'local.email' **: email }, **function**(err, user) {
**if **(err)
**return **done(err);
**if **(user) {
**return **done(**null**, **false**);
*// Using 'loginMessage instead of signupMessage because it's used by /connect/local'
*} **else **{
**var **user = req.**user**;
user.**local**.**email **= email;
user.**local**.**password **= user.generateHash(password);
user.save(**function **(err) {
**if **(err)
**return **done(err);
**return **done(**null**,user);
});
}
});
} **else **{
*// user is logged in and already has a local account. Ignore signup. (You should log out before trying to create a new account, user!)
***return **done(**null**, req.**user**);
}
});
}));
};
module.exports = *myLocalConfig*;
Again go to the root directory and follow the commands
mkdir models
cd models
mkdir user
cd user
touch index.js
Paste the following code and make the user model:
*// load the things we need
***var **mongoose = require(**'mongoose'**);
**var **bcrypt = require(**'bcrypt-nodejs'**);
*// define the schema for our Photographer model
***var **userSchema = mongoose.Schema({
**local **: {
**email **: String,
**password **: String
}
});
*// generating a hash
*userSchema.**methods**.generateHash = **function**(password) {
**return **bcrypt.*hashSync*(password, bcrypt.*genSaltSync*(8), **null**);
};
*// checking if password is valid
*userSchema.**methods**.validPassword = **function**(password) {
**return **bcrypt.*compareSync*(password, **this**.**local**.**password**);
};
*// create the model for photographers and expose it to our app
*module.exports = mongoose.model(**'User'**, userSchema);
Here’s our boilerplate code is ready. Go to the root directory and run
node server.js
You must see: “The magic happens on port 8080”
Let’s complete the auth route. Paste the code in ./routes/auth/index.js
**var **express = require(**'express'**);
**var **router = express.Router();
**var **passport = require(**'passport'**);
router.**post**(**'/signup'**, passport.authenticate(**'local-signup'**, {
**successRedirect **: **'/auth/profile'**,
**failureRedirect **: **'auth/signup'
**}));
router.**post**(**'/login'**, passport.authenticate(**'local-login'**, {
**successRedirect **: **'/auth/profile'**,
**failureRedirect **: **'auth/login'
**}));
router.get(**'/profile'**, *isLoggedIn*, (req, res) => {
res.**status**(200).**json**(req.**user**);
});
router.get(**'/logout'**, *isLoggedIn*, (req, res) => {
req.logout();
res.**status**(200).**json**({
**'message'**: **'successfully logout'
**});
});
module.exports = router;
*//route middleware to ensure user is logged in
***function ***isLoggedIn*(req, res, next) {
**if **(req.isAuthenticated())
**return **next();
res.**status**(400).**json**({
**'message'**: **'access denied'
**});
}
So we are done for signIn, signOut, SignUp and viewProfile Section.
Here we create two routing, one for the guest and another for the authenticated users.
Go to the ./routes/test/index.js and it would be like this:
**var **express = require(**'express'**);
**var **router = express.Router();
router.get(**'/guest'**, (req, res) => {
res.**status**(200).**json**({
**'message'**: **"This is not secured guest routing"
**});
});
router.get(**'/user'**, *isLoggedIn*, (req, res) => {
res.**status**(200).**json**({
**'message'**: **"This is secured user routing"
**});
});
module.exports = router;
*//route middleware to ensure user is logged in
***function ***isLoggedIn*(req, res, next) {
**if **(req.isAuthenticated())
**return **next();
res.**status**(400).**json**({
**'message'**: **'access denied'
**});
}
If you have come this far, then congratulation, you implements the basic open authorization using passport js and secure specific routing.
We will use postman to check the API.
Create an user:
Request Type: POST Headers: { ‘content-type’: ‘application/json’ } Address: localhost:8080/auth/signup Body: raw
{
“email”: “test[@mail.com](mailto:mail2@mail.com)”,
“password”: “1234567890”
}
In response we will get user id and hashed password:
{
“_id”: “59c7d5f7294b322b0321ad6a”,
“__v”: 0,
“local”: {
“password”: “$2a$08$varXSszNbVsFH85B3Ewk4.Q4qhXRJBeyDrZNLu7vrlJhoBefpc50S”,
“email”: “[test@mail.com](mailto:test@mail.com)”
}
}

When we create an user we will be automatically logged in.
Now Let say, A user already exist and wants to logged in,
Log in an User:
Request Type: POST Headers: { ‘content-type’: ‘application/json’ } Address: localhost:8080/auth/login Body: raw
{
“email”: “test[@mail.com](mailto:mail2@mail.com)”,
“password”: “1234567890”
}
In response we will get Logged in user information:
{
“_id”: “59c7d5f7294b322b0321ad6a”,
“__v”: 0,
“local”: {
“password”: “$2a$08$varXSszNbVsFH85B3Ewk4.Q4qhXRJBeyDrZNLu7vrlJhoBefpc50S”,
“email”: “[test@mail.com](mailto:test@mail.com)”
}
}

Profile of a logged in user:
To get the information of a logged in user,
Request Type: GET Address: localhost:8080/auth/profile
In response we will get the users profile:
{
“_id”: “59c7d5f7294b322b0321ad6a”,
“__v”: 0,
“local”: {
“password”: “$2a$08$varXSszNbVsFH85B3Ewk4.Q4qhXRJBeyDrZNLu7vrlJhoBefpc50S”,
“email”: “[test@mail.com](mailto:test@mail.com)”
}
}

Log out of an user:
To log out from the app,
Request Type: GET Address: localhost:8080/auth/logout
In response we will get the message:
{
"message": "successfully logout"
}
Open authorization is completed here.

When user is not logged in,
Request Type: GET Address: localhost:8080/test/user
{
“message”: “access denied”
}

Request Type: GET Address: localhost:8080/test/guest
{
“message”: “This is not secured guest routing”
}

When user is logged in,
Request Type: GET Address: localhost:8080/test/user
{
“message”: “access denied”
}

Request Type: GET Address: localhost:8080/test/guest
{
“message”: “This is not secured guest routing”
}

So Here we are, completed the basic open authentication using passport.js in node.js and express.js server. In future I will go through authentication using facebook, google, twitter and like other stuff. Stay tuned and if there is a confusing term or something, response below or create an issue in *github*.