Building a simple security model for Node server.

Building a simple security model for Node server.

In this article, we’re going to add a simple security model to the application, which will accept a login, validate a user, redirect to a secure page, enable a logout, and catch any errors which occur during the process. Let’s get started.

Creating a Security Model

The first thing we’re going to do is create a service for the Node server. This will perform our authentication of a user, expose our logged-in user information to the application, and handle the invalidation of the user once they log out of the system.

Now, remember, we’re calling this a simple security model, so be aware that there is no database involved. There are no hashed passwords. There are no tokens passed around. We’re going simple just to demonstrate the idea of security. Now, let’s take a look at the user.service.js module:

module.exports = {
 status: "",
 user: {
   userName: "admin",
   password: "admin",
   authenticated: false,
   status: this.status
 },
 validateUser: function(login) {
   console.log("this.user: ", this.user, " and login: ", login);
   if (
     login.username === this.user.userName &&
     login.password === this.user.password
   ) {
     this.user.authenticated = true;
     this.status = "You have successfully signed in.";
     return true;
   } else {
     this.status = "Invalid useranme or password.";
     this.user.authenticated = false;
     return false;
   }
 },
 getUserInfo: function() {
   if (this.user.authenticated) {
     return {
       username: this.user.userName,
       authenticated: this.user.authenticated,
       status: this.status
     };
   }
 },
 logoutUser: function() {
   this.status = "You are now signed out.";
   this.user.authenticated = false;
 }
};

From top to bottom, I’ll walk you through this code file. First, we’re creating a simple module exports that expose a handful of functions and properties. We are exposing both a status and a user at this time. Of the two, we’ll be using the User object the most throughout the execution of logging in and logging out.

The first function is validateUser, which is looking for a simple parameter called login. This parameter will be an object that contains the username and the password being passed from the user interface. If both parameters match the static user information that we have in the userobject, we will set a user.authenticated property to true and set the status to a success message.

The second function of the module is getUserInfo. This function will return a simple user object back to the calling code. Because of the need to be authenticated, we first check our internal user object to determine if it has been authenticated. If it has, we then create a literal object on-the-fly containing the username, the current status of the user, and a boolean flag of authenticated.

Our last function is a simple logoutUser function which accepts no parameters. The function will set the current status to a signed out status and flips the authenticated status flag to false.

Now that we have created our security model, let’s go on and use it for logging in and enabling a secure page for our user.

Securing Our Routes and Display a Page

In our routes directory and inside the index.js file, we have all of the routes for our application. At this point, we’ve added in several more to enable logging in and logging out and for our secure page.

The first route that we have created has been a simple GET route to direct the user to a login page.

app.get("/login/", function(req, res, next) {
     let data = {
       title: "Sign In"
     };
     res.render("static/login", { data });
   });

The markup for that page looks like this:

{{> header }}
{{> navigation }}
<div class="row justify-content-center align-items-center" style="height:60vh">
           <div class="col-4">
               <h2><i class="fa fa-sign-in" aria-hidden="true"></i> Sign In</h2>
               <div class="card">
                   <div class="card-body">                       
                       <form action="/checklogin" method="POST" autocomplete="off">
                           <div class="form-group">
                               <label>Username</label>
                               <input type="text" class="form-control" name="username">
                           </div>
                           <div class="form-group">
                               <label>Pasword</label>
                               <input type="password" class="form-control" name="password">
                           </div>
                           <button type="submit" id="sendlogin" class="btn btn-primary">login</button>

                           <a href="/" class="btn btn-outline-secondary">cancel</a>
                       </form>
                   </div>
               </div>
           </div>
       </div>
{{> footer }}

This page has a simple Bootstrap 4 form centered in the page. There are two text fields on the form along with a submit button. The fields are looking for the username and for the password. Upon clicking the submit button, the form will POST back to the server using this code:

<form action="/checklogin" method="POST" autocomplete="off">

Notice that we’re posting to the /checklogin route with the information from the form. Now for the checklogin route code:

app.post("/checklogin", function(req, res, next) {
     let login = {
       username: req.body.username,
       password: req.body.password
     };
     let authenticated = userService.validateUser(login);
     if (authenticated) {      
       // simulating a database call
       let timer = setTimeout(function() {
         user = userService.getUserInfo();                
         clearInterval(timer);
         res.redirect(302,"/secure");        
       }, 1000);
     } else {      
       res.redirect(302, "/login/");
       res.end();
     }
   });

From the request, the code is going to look for two parameters sent back to the server. We’re going to assign those two values to an object literal called login’ with the properties of username and password. We then create a local variable called authenticated and capture the return value from our userService.validateUser function after we pass in the login object.

Assuming that we have a valid login object,authenticatedwill pass the if test and now sets a global user object with the contents that we requested from the userService.getUserInfo function. We’ve surrounded the setting of the user object and the redirect with a time out to simulate hitting a database. Once the timeout finishes, we use the response object’s redirect function to set a response status of 302 (found) and redirects the user to the /secure route. If we fail to authenticate, we are going to simply redirect the user back to the login form and kill the response.

We’ve logged in and we’re being redirected to another route. This is great, but what does this new route do for us? Let’s take a look at the code:

app.get("/secure/", function(req, res, next){
     if(user.authenticated){
       let data = {
         title: "Secure Page",
         links: fileListing.CreatedFileList(enums.RouteEnums().unknown),
         contents: "",
         user: user,
         active: true
       };
       res.render('static/secure', { data });
     } else {
       res.redirect(302, "/login/");
       res.end();
     }    
   });

Once we hit the/secure/route, the first thing we’re going to do is check to see if the user can be here by checking the user.authenticated property. Remember, if we successfully logged in, this property should be true.

Upon passing through the if statement, we can now set the actual page data as we have been doing for most of our other pages. Notice that on the links property we’re still using the fileListing.CreatedFileList function. This time, though, we’re going to be passing a value of unknown to the listing because the file is not part of the view/pages directory. This was done so that we can still have global navigation across the top of the application. We also have a user property where we will assign the global user object to it. This way, we can utilize the information about the user on the views we access.

Once our data object is set, we now will render the view static/secure view to the browser. If at any time we are not authenticated, this route will redirect the user back to the /login/ route for the user to try again.

Our secured page doesn’t have much going on with it right now, but we do utilize the information about the user in it. Here is the Handlebars view:

{{> header }}
{{> navigation }}
<h3><i class="fa fa-lock" aria-hidden="true"></i> Signed In</h3>
<hr />
<p>{{data.user.status}}</p>
{{> footer }}

Remember that we set the status of the user object during login? Now, we’re going to display that information using the Handlebars double curly brace helper and display the data.user.status to the user.

Now for the navigation bar. To begin with, the navigation has a sign in link, but we want to be able to change that depending on the status of the user. Let’s take a look at the markup for the navigation:

<div class="navbar-nav">
        {{#if data.user.authenticated}}
         <span class="text-light navbar-text">Welcome {{data.user.username}}  </span>
         <a href="/logout" class="nav-link">Sign Out</a>
       {{else}}
         <a href="/login" class="nav-link">Sign In</a>
       {{/if}}
     </div>

We’re going to use one of Handlebars view helpers and do an if conditional on the data.user.authenticated property which we set back in the /secure/ route. If this passes, the markup allows the user name to be displayed using the curly braces and it will display a new hyperlink which directs to the /logout/ route. If the conditional fails, the user of the application only sees the link for signing in.

Now that we’ve gone through signing into the application and getting redirected to a secure page that checks our authentication, let’s go ahead and sign back out. Clicking the link found in the navigation bar will send us to a simple GET route called /logout which contains the following code:

app.get("/logout", function(req, res) {
    userService.logoutUser();
    user = {};
    res.redirect(302, "/");
  });

This route does three simple things. We set the authentication of the users authenticated flag to false using the userService.logoutUser function. We set the global user object to an empty object literal. And we now redirect the user to the index of the site.

There we have it. Our simple security model has been implemented, which allows a user to login and authenticate via a service. The valid user is then redirected to a secure page and the navigation bar is updated with the status and changes from Sign In to Sign Out. This model can definitely be expanded by adding database access to store additional users. Passwords should be stored in some non-human readable form when in the database. JSON web tokens should be generated and passed to the front end to validate any request made back and forth from the front end and the back end.

Thanks for reading : Let's share it!

node-js javascript

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

How to Hire Node.js Developers And How Much Does It Cost?

A Guide to Hire Node.js Developers who can help you create fast and efficient web applications. Also, know how much does it cost to hire Node.js Developers.

Top 7 Most Popular Node.js Frameworks You Should Know

Node.js is an open-source, cross-platform, runtime environment that allows developers to run JavaScript outside of a browser. In this post, you'll see top 7 of the most popular Node frameworks at this point in time (ranked from high to low by GitHub stars).

Hire Node.JS Developers | Skenix Infotech

We are providing robust Node.JS Development Services with expert Node.js Developers. Get affordable Node.JS Web Development services from Skenix Infotech.

Node.js for Beginners - Learn Node.js from Scratch (Step by Step)

Node.js for Beginners - Learn Node.js from Scratch (Step by Step) - Learn the basics of Node.js. This Node.js tutorial will guide you step by step so that you will learn basics and theory of every part. Learn to use Node.js like a professional. You’ll learn: Basic Of Node, Modules, NPM In Node, Event, Email, Uploading File, Advance Of Node.

Hands on with Node.Js Streams | Examples & Approach

The practical implications of having Streams in Node.js are vast. Nodejs Streams are a great way to handle data chunks and uncomplicate development.