NodeJS + Postgres DB + Passport JWT + Passport Local Login and Authentication
Tags: passport, javascript, node, express
Published: 2022-07-20 06:31:16

Hi,

Here I am writing my first blog 😇 about how do we connect a simple [NodeJS Application] 😎(https://www.npmjs.com/package/express) to [Postgres](https://www.postgresql.org/) and use [PassportJS](https://www.npmjs.com/package/passport) for authentication and authorization.

So the basic machine setup would look like this:

`Node JS - v12 or above`
`pgAdmin for DB Connectivity`
`npm for creating and installing the dependencies`



> **Step 1:** 

Let's create a simple npm module using `npm init` in the directory you want to create your application.

`> npm init`

It will ask you the below questions for the configuration of the 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ww1y84tngtvp42lx4ino.png)

You can hit enter for every question or you can add your own configs, I am using the default ones.


> **Step 2:**
Now we need the dependencies which needs to be installed for our application to use while we compile the code:

Here is how my package.json looks like:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5k5usam8nr3uc1b5ucg9.png)

Here is the command you can run to install the dependencies:

`npm i --save bcrypt-nodejs cors express jsonwebtoken nodemon passport passport-jwt passport-local pg pg-hstore sequelize`

Let's catch all the dependencies and their work for us:

- `bcrypt-nodejs`: It will help us to encrypt and decrypt the password when we create a new user.

- `cors`: To allow _CROSS ORIGIN REQUESTS_ install if you want or need.

- `express`: It will create a server for us to use it's routes.

- `jsonwebtoken`: To create the JWT Token for the API Authorizations.

- `passport`: For easy authentication of the User.

- `passport-jwt`: For JWT Authorization.

- `passport-local`: For LocalStrategy of the Login Authentication

- `pg pg-hstore sequelize`: For Accessing the Postgres DB


> **Step 3:**

Let's create a simple server to kick start our project:

here is what I have in my `index.js` file:

```javascript
// project/index.js 


const express = require('express')
const db = require('./models')
var cors = require('cors')
const app = express()
const port = 3000
app.use(express.json());
app.use(cors())

db.sequelize.sync().then(() => {
    console.log("Synced")
}).catch(err => console.err(err))

app.get('/', (req, res) => {
    res.send('Hello World!')
})

require('./routes/user.route')(app)

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})
```

What this statement does is:

```javascript
db.sequelize.sync().then(() => {
    console.log("Synced")
}).catch(err => console.err(err))
```

to check if the `Postgres DB` has been connected and is sequelizing it.

And then the routes which we are going to create on the very next step.

And our server start:

Comment out this line

`require('./routes/user.route')(app)`

and run `npm run dev` and see if the application is `Synced` and is running on Port 3000

if it shows below:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3lffqqltxxvsnof1c4er.png)

YAYYYY....!!! You have created a express server now.

> **Step 4:**


The fun part begin here:

 - Let's create the routes

```javascript
// project/routes/user.route.js


module.exports = app => {

    // Import of the controller
    const user = require('../controller/user.controller')

    // Creating the router instance
    const router = require('express').Router();

    // TO create the user
    router.post('/user', user.create)

    // To Login the user using Passport Local Strategy
    router.post('/user-passport-login', user.loginWithPassport)

    // Pass the router instance to the App.
    app.use('/api/v1', router)
}
```

Each route has it's own defination, let's create our very first controller now:

```javascript
// project/controller/user.controller.js

const db = require("../models");
const User = db.user;
const passportLocal = require('../config/passportLocal')

// To create a new user in the DB

function create(req, res) {
    const userdata = {
        username: req.body.username,
        password: req.body.password
    }
    User.create(userdata).then(data => {
        return res.send(data)
    }).catch(err => {
        console.warn(err)
    })
}


// To Login the user using Passport

async function loginWithPassport(req, res) {
    return await passportLocal.authenticate('local', function (err, response) {
        if (response) {
            return res.send({
                msg: "Login Success",
            })
        }
        if (!response) {
            return res.send({
                msg: "Failed"
            })
        }
    })(req, res)
}

```

wait wait...!!

why this line:

```
    })(req, res)
```

The `loginWithPassport` is a self calling function which would have the `req` and `res` as the parameters, since we need to return the calculated response from the controller to the API, we also need the request params.

> **Step 5:**

Let's create our `Models` now:

```javascript
// project/models/user.model.js

var bcrypt = require('bcrypt-nodejs');

module.exports = (sequelize, DataTypes) => {

    // To get the feasiblity of the Sequelize ORM
    const User = sequelize.define("user", {
        username: {
            type: DataTypes.STRING,
            primaryKey: true
        },
        password: {
            type: DataTypes.STRING
        },
    });

    // It will convert each password into the Hashed String for maintaining the security
    User.beforeSave((user) => {
        if (user.changed('password')) {
            user.password = bcrypt.hashSync(user.password, bcrypt.genSaltSync(10), null)
        }
    })

    // It will compare the password to the passed string using the bcrypt algo, and will return the result
    User.prototype.comparePassowrd = function (pass, cb) {
        bcrypt.compare(pass, this.password, function (err, isMatch) {
            if (err) {
                return cb(err)
            }
            cb(null, isMatch)
        })
    }
    return User;
};
```

We have created the Model but right now it is not being used it is just a kind of Schema, now let's do the tricky part, let's create a DB Table in the pgAdmin using the below code:


```javascript
// project/models/index.js

const dbConfig = require('../db.config')
const Sequelize = require('sequelize')

const sequelize = new Sequelize(dbConfig.DB, dbConfig.USER, dbConfig.PASSWORD, {
    host: dbConfig.HOST,
    operatorAliases: false,
    dialect: dbConfig.dialect,
    pool: dbConfig.pool
})

const db = {}

db.Sequelize = Sequelize
db.sequelize = sequelize
db.user = require('./user.model.js')(sequelize, Sequelize)

module.exports = db;
```

`dbConfig.js`

```javascript
// project/dbConfig.js

module.exports = {
    HOST: "localhost",
    USER: "harishsoni",
    PASSWORD: "admin",
    DB: "testDB",
    dialect: "postgres",
    pool: {
        max: 5,
        min: 0,
        acquire: 30000,
        idle: 10000
    }
}
```
Here is the line from the index.js, which is using the above Sequelization and Syncing the DB:

```
const db = require('./models')
```

> **Step 3:**


Now the final Part let's create the `passportLocal.js` file which will contain the main business logic to check the use authentication.

```javascript
// project/config/passportLocal.js

const passport = require('passport')
const LocalStratery = require('passport-local').Strategy
const db = require('../models')

// Creating the passport instance to be used from the controller.

passport.use(new LocalStratery({

    // if you use any different name for the username field, you can pass the key here
    usernameField: 'username'
}, async function (username, password, done) {
    // findByPk is a Sequelize function which returns the data if it finds the primary key with the value passed
    return await db.user.findByPk(username).then(async data => {

        // Check if the user is there in the DB:
        if (!data) {
            return done(null, null)
        }

        // If the user is correct, then let's see if he has entered the correct password.
        await data.comparePassowrd(password, (err, userData) => {
            return done(null, userData)
        })
    }).catch(err => { throw err })
}))


// For Storing the user id in the session {req.session.passport.user = {id: '..'}}
passport.serializeUser(function (user, cb) {
    cb(null, user)
})

// For checking if the user has an active session.
passport.deserializeUser(function (obj, cb) {
    cb(null, obj)
})

module.exports = passport
```

Here is how the passport configuration will look to login the user

So combining all we will have something like this:

```javascript
project
│   index.js
│   db.config.js
│   package.json
│
└───models
│    user.model.js
│    index.js
│   
└───config
│    passportLocal.js
│   
└───controller
│    user.controller.js
│   
└───routes
      user.route.js


```

🥳🥳🥳 We are done with the setup now the time to run and see if the code works (If works god knows how, and if not we need to know why  😂 😂 😂 😂 😂)

🤞🤞 Here we gooooooo.....!!!!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9fefieep11tfn99jeyja.gif)

🧐🧐🧐 It Worked::::::::::::

Let's check the API's NOW:

🤞🤞🤞🤞🤞🤞🤞🤞🤞🤞


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yauucfrf8m0uhdj036yo.gif)


Yeah, it worked: 😎😎😇😇

```
Any suggestion are welcome:
```

Repo Link: https://github.com/harish9312/passport-auth-node