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 and use PassportJS 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
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:
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 Authenticationpg 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:
// 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:
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:
YAYYYY....!!! You have created a express server now.
Step 4:
The fun part begin here:
- Let's create the routes
// 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:
// 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:
// 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:
// 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
// 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.
// 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:
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.....!!!!
π§π§π§ It Worked::::::::::::
Let's check the API's NOW:
π€π€π€π€π€π€π€π€π€π€
Yeah, it worked: ππππ
Any suggestion are welcome:
Top comments (0)