Node.js use passport with LocalStrategy in Authentication Part 1

        When we implement the authentication of users, it is common to use passport module. It supports different methods of authentication: username and password(local), Bear (token), OAuth(authenicated by another trusted provider, eg Google, Facebook).....

        This post records my learning of using passport with local strategy  as my learning. The completed source code is in github repository.

First, we do the basic setup by applying express and body-parser module. Then we create 3 routes for testing.   

import express from "express";
import bodyParser from "body-parser";

const app = express();

const PORT = 6000;

app.use(bodyParser.urlencoded({extends:false}));
app.use(bodyParser.json());

app.get("/login", (req, res) =>{
return res.send("this is login page. Don't need authentication");
});

app.post("/login", (req, res)=>{
return res.send("POST login route");
});

app.get("/secrets", (req, res) =>{
return res.send("This is secrets page. Access this page after login");
});

app.listen(PORT, () =>
console.log(`start listening to port ${PORT}`)
);

        Use postman to verify the code. It get the correct response when access http:localhost:6000/login

postman get server response succefully 

Module passport and passport-local

        We install npm module passport and passport-local and import them just below body-parser. Instead of implementing multiple concrete authentication methods, module passport only provide the general interface. It helps to keep the program smaller in size as developer only loads the required authentication methods(or  "Strategy" in term of passport) into passport. The strategy defined in passport-local module will take username(or email in some application) and password as credential.

The code show first and explanation follows:

import express from "express";
import bodyParser from "body-parser";
import passport from "passport";
import {Strategy} from "passport-local";

const app = express();

const PORT = 6000;

app.use(bodyParser.urlencoded({extends:false}));
app.use(bodyParser.json());

app.get("/login", (req, res) =>{
return res.send("this is login page. Don't need authentication");
});

app.post(
"/login",
passport.authenticate(
"local",
{
successRedirect: "/secrets",
failureRedirect: "/",
session:false
}
)
);

app.get("/secrets", (req, res) =>{
return res.send("This is secrets page. Access this page after login");
});

app.listen(PORT, () =>
console.log(`start listening to port ${PORT}`)
);


const user = {name: "Tom", password:"123456"};

function getUserInfo(username){
if(username === user.name)
return user;
return null;
}

passport.use(
"local",
new Strategy(
{usernameField: "username", passwordField:"password"},
function verify(username, password, cb){
const userCredentials = getUserInfo(username);
if(!userCredentials)
return cb(null, false, { message:"User does not exist"});
if(password === userCredentials.password){
const userInfo = {};
userInfo.name = userCredentials.name;
//only provide the necessary info to callback function
return cb(null, userInfo);
}

return cb(null, false, {message: "incorrect password"});

}
)
);

       First, look at the code below app.listen() to see how to load the strategy into passport. User object is hard coded here for simplicity(for real case, user information should be stored in database. This will show later.). We load the strategy(authentication method) by calling passport.use() method. The 1st argument gives a name to this strategy. Since we can load multiple strategy into passport, we need a reference name to specify which strategy is used at what condition.

        The local strategy constructor has two arguments: option and verify function. The strategy parse the request body of POST action and pass argument to the verify function. It pass the body's property , which name equal to the value of usernameField as 1st argument of verify function and pass property which name equal to value of passwordField as 2nd argument. The 3rd argument of verify function is callback function. We pass message as 1st argument of the callback function(cb) when there is error. If user is authenticated, we pass user information as 2nd argument of the callback function for later use. We can add a object in the 3rd argument as extra context for application-specific use (e.g message that explain failure reason).

        We now has loaded the local strategy into passport and let's invoke it at the point we want authentication. When client submit username and password to login, the server goes to app.post("/login", .......) this route. Therefore, we call passport.authenticate() method here to execute the authentication process. 1st argument is the name of strategy we want to use (we name it above in the method passport.use()). 2nd argument provide simple operation of the result of authentication process. The property successRedirect is the GET route the server redirect to when authentication success while The property failureRedirect is the GET route when authentication failure. I will talk about session later, set false at this moment for .

The postman result when authentication success :

response when access "/secret" route

 The postman result when authentication fail :

response same as when access GET "/login" route

However, if there is error(1st arugemnt of cb function is not null inside the verify function when creating the local strategy), the server response a html file instead of failureRedirect. Since we hard copy user information, you may wonder why there is error. In real case, we will access database to get user information. Errors may occur at accessing the database.

 The postman result when there is error in cb function. We can use try-catch to handle the exception error for this case.

Postman result when pass a string to 1st arugment of Strategy cb function

You can see the source code (v1.1) up to this moment in github. 

If we want to control how the server respond instead of redirecting another route, please see Part 2 post.

 

 

For more detail, please go to the npm module page of passport and passport-local api.

 

 


 

Comments

Popular posts from this blog

Use okhttp to download file and show progress bar

Download File into app specific storage with Retrofit

Unzipp file with Zip4j library