Roadmap to becoming a developer in 2022
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

9.0 KiB

HTTP is the internet protocol that standardizes how clients and servers interact with each other. When you open a website, among other things, HTTP is the protocol that helps load the website in the browser.

HTTP is Stateless

HTTP is a stateless protocol which means that each request made from the client to the server is treated as a standalone request; neither the client nor the server keeps track of the subsequent requests. Sessions allow you to change that; with sessions, the server has a way to associate some information with the client so that when the same client requests the server, it can retrieve that information.

In this guide, we will learn what is Session-Based Authentication and how to implement it in Node.js. We also have a separate visual guide on Session-Based Authentication as well that explains the topic visually.

What is Session-Based Authentication?

Session-based authentication is a stateful authentication technique where we use sessions to keep track of the authenticated user. Here is how Session Based Authentication works:

  • User submits the login request for authentication.
  • Server validates the credentials. If the credentials are valid, the server initiates a session and stores some information about the client. This information can be stored in memory, file system, or database. The server also generates a unique identifier that it can later use to retrieve this session information from the storage. Server sends this unique session identifier to the client.
  • Client saves the session id in a cookie and this cookie is sent to the server in each request made after the authentication.
  • Server, upon receiving a request, checks if the session id is present in the request and uses this session id to get information about the client.

And that is how session-based authentication works.

Session-Based Authentication in Node.js

Now that we know what session-based authentication is, let's see how we can implement session-based authentication in Node.js.

Please note that, for the sake of simplicity, I have intentionally kept the project strictly relevant to the Session Based Authentication and have left out a lot of details that a production-ready application may require. Also, if you don't want to follow along, project codebase can be found on GitHub.

First things first, create an empty directory that will be holding our application.

mkdir session-auth-example

Now run the following command to setup a sample package.json file:

npm init -y

Next, we need to install the dependencies:

npm install express express-session

Express is the application framework, and express-session is the package that helps work with sessions easily.

Setting up the server

Now create an index.js file at the root of the project with the following content:

const express = require('express');
const sessions = require('express-session');

const app = express();

app.use(sessions({
  secret: "some secret",
  cookie: {
    maxAge: 1000 * 60 * 60 * 24 // 24 hours
  },
  resave: true,
  saveUninitialized: false,
}));

app.use(express.json());
app.use(express.urlencoded({extended: true}));

// @todo register routes

app.listen(3000, () => {
  console.log(`Server Running at port 3000`);
});

The important piece to note here is the express-session middleware registration which automatically handles the session initialization, cooking parsing and session data retrieval, and so on. In our example here, we are passing the following configuration options:

  • secret: This is used to sign the session ID cookie. Using a secret that cannot be guessed will reduce the ability to hijack a session.
  • cookie: Object containing the configuration for session id cookie.
  • resave: Forces the session to be saved back to the session store, even if the session data was never modified during the request.
  • saveUninitialized: Forces an "uninitialized" session to be saved to the store, i.e., saves a session to the store even if the session was not initiated.

Another important option is store which we can configure to change how/where the session data is stored on the server. By default, this data is stored in the memory, i.e., MemoryStore.

Look at the express-session documentation to learn more about the available options.

Creating Handlers

Create a directory called the handlers at the project's root. This is the directory where we will be placing all the route-handling functions.

Now let's create the homepage route, which will show the welcome message and a link to log out for the logged-in users and redirect to the login screen for the logged-out users. Create a file at handlers/home.js with the following content.

module.exports = function HomeHandler(req, res) {
  if (!req.session.userid) {
    return res.redirect('/login');
  }

  res.setHeader('Content-Type', 'text/HTML')
  res.write(`
    <h1>Welcome back ${req.session.userid}</h1>
    <a href="/logout">Logout</a>
  `);

  res.end()
}

At the top of this function, you will notice the check req.session.userid. req.session is automatically populated using the session cookie by the express-session middleware that we registered earlier. req.session.userid is one of the data fields that we will set to store the userid of the logged in user.

Next, we need to register this handler with a route. Open the index.js file at the root of the project and register the following route:

const HomeHandler = require('./handlers/home.js');

app.get('/', HomeHandler);

Next, we have the login page, redirecting the user to the home screen if the user is logged in or showing the login form. Create a file at handlers/login.js with the following content:

module.exports = function LoginHandler(req, res) {
  if (req.session.userid) {
    return res.redirect('/');
  }

  res.setHeader('Content-Type', 'text/HTML')
  res.write(`
    <h1>Login</h1>
    <form method="post" action="/process-login">
      <input type="text" name="username" placeholder="Username" /> <br>
      <input type="password" name="password" placeholder="Password" /> <br>
      <button type="submit">Login</button>
    </form>
  `);

  res.end();
}

Again, at the top of the function, we are simply checking if we have userid in the session (which means the user is logged in). If the user is logged in, we redirect them to the homepage; if not, we show the login screen. In the login form, we have the method of post, and we submit the form to /process-login. Please note that, for the sake of simplicity, we have a simple HTML string returned in the response, but in a real-world application, you will probably have a separate view file.

Let's first register this page and then implement /process-login endpoint. Open the index.js file from the root of the project and register the following route:

const LoginHandler = require('./handlers/login.js');

app.get('/login', LoginHandler);

Next, we have to implement the functionality to process the login form submissions. Create a file at handlers/process-login.js with the following content:

module.exports = function processLogin(req, res) {
  if (req.body.username !== 'admin' || req.body.password !== 'admin') {
    return res.send('Invalid username or password);
  }

  req.session.userid = req.body.username;

  res.redirect('/');
}

As you can see, we are simply checking that the username and password should both be admin and admin for a user to authenticate successfully. Upon finding valid credentials, we set the userid in the session by updating req.session.userid. Similarly, you can set any data in the session. For example, if we wanted to store the user role, we would do the following:

req.session.role = 'admin'

And later access this value out of the session anywhere in the subsequent requests.

Register this route in the index.js file at the root of the project:

const ProcessLoginHandler = require('./handlers/process-login.js');

app.post('/process-login', ProcessLoginHandler);

Finally, we have the logout functionality. Create a file at handlers/logout.js with the following content:

module.exports = function Logout(req, res)  {
  req.session.destroy();
  res.redirect('/');
}

We reset the session by calling req.session.destroy() and then redirecting the user to the homepage. Register the logout handler in the index.js file using the following:

const LogoutHandler = require('./handlers/logout.js');

app.get('/logout', LogoutHandler);

Running the Application

Open the package.json file and register the start script as follows:

"scripts": {
  "start": "node index.js"
},

Now you can start the application by running the following command:

npm run start

Now, if you open up your browser and visit the project at http://localhost:3000 you will be able to see the Session-Based Authentication in action.