How to create a simple login functionality in Express

Session and cookies are primarily used to build the login process for any website. Let's build this concept using the express-session npm package.

Gohit Varanasi
Webtips

--

Credits: Photo by Micah Williams on Unsplash

There are several websites including Medium.com which all have one thing in common. They need you to LOGIN. While it’s obvious why we need it, let’s explore how is it implemented. As always, Express will be the backend service for running our local website to showcase this example. But before jumping to the code, let us spend a few minutes behind the concepts.

How Session and cookies complete the Login process?

HTTP is stateless, the server doesn’t know who you are (not even the second or even the third time 😃). Due to this nature of HTTP, Servers and Clients use cookies to recognise each other. Sessions, on the other hand, store all the data of the Client on the Server. As an analogy, Sessions are individual rooms in a hotel, and cookies are the keys to those rooms.

Time to write some code !!!

This section will be fun where all the above concepts spring into action. The full code listing for this is placed in the end. We will do a code walkthrough and discuss about the individual routes and middlewares used to achieve our login functionality.

express-session middleware
The first section of the code has the following lines

app.use(session({secret:'Keep it secret'
,name:'uniqueSessionID'
,saveUninitialized:false}))

There is a lot happening in those three lines of code. Firstly, express-session is a middleware and will have access to both req and res objects. It also uses a store (default MemoryStore) to save the data. With app.use() , we ensure this middleware is triggered for every single request to the Server irrespective of the routes. Now let us break down the working of express-session .

  1. On initialisation, it checks the req object for any cookies with the name ‘uniqueSessionID’ .
  2. If it finds one, it will look up the value of the ‘uniqueSessionID’ in the store and populate the req.session object.
  3. If there are no cookies found or if the value of the cookie cannot be found in the store, it creates a new value for the ‘uniqueSessionID’ and a new req.session object but does not save it in the store unless changed. (saveUninitialized:false)
  4. If the data (req.session object) is changed, it gets saved to the store and a cookie will be created in the res object and passed on to the next handler.

The above steps will occur for every request and the logic can be applied for every other route as below.

a) http://localhost:3000

So applying the express-session steps from above, there is nothing saved in the store, and no cookies sent in the response for the first time. But subsequent requests after authentication will have cookies in the requests and also data in the store. Let’s see below how a session is created with its data.

b) http://localhost:3000/authenticate

Please refer this article which talks more about body-parser middleware.
Now, applying the same express-session steps, four important things happen at the end of this request.

  1. req.session object is populated (loggedIn and username properties) and saved in the store.
  2. A cookie is created and passed into the response in the Header:Set-Cookie:uniqueSessionID=s%3AiGn4lXP-Jhf6RahxDYQHgnCWTvq8C7u4.1YPir9YmqXlhLJXDSQb%2Fdw7PwR6EOQWAgwZP7O%2BZ7XQ; Path=/; HttpOnly
  3. All subsequent requests will have the cookie value and its corresponding req.session object in the store.
  4. The above session data will now be accessible by the other routes localhost:3000 and localhost:3000/dashboard

c) http://localhost:3000/logout

If we check the listing, session.destroy will remove the req.session object from the store and will remove any cookies from the res object.

Full listing of the code

const express = require('express');
const session = require('express-session')
const bodyParser = require('body-parser')
const path = require('path')
const app = express();
const port = 3000;
app.use(session({secret:'Keep it secret'
,name:'uniqueSessionID'
,saveUninitialized:false}))
app.get('/',(req,res)=>
{
if(req.session.loggedIn)
res.redirect('/dashboard')
else
res.sendFile('home.html',{root:path.join(__dirname,'public')})
})
app.get('/dashboard',(req,res)=>
{
if(req.session.loggedIn)
{
res.setHeader('Content-Type','text/html')
res.write('Welcome '+req.session.username+' to your dashboard')
res.write('<a href="/logout">Logout</a>')
res.end()
}
else
res.redirect('/login')
})
app.get('/login',(req,res)=>
{
res.sendFile('login.html',{root:path.join(__dirname,'public')})
})
app.post('/authenticate'
,bodyParser.urlencoded()
,(req,res,next)=>
{
// Actual implementation would check values in a database
if(req.body.username=='foo'&&req.body.password=='bar')
{
res.locals.username = req.body.username
next()
}
else
res.sendStatus(401)
}
,(req,res)=>
{
req.session.loggedIn = true
req.session.username = res.locals.username
console.log(req.session)
res.redirect('/dashboard')
})
app.get('/logout',(req,res)=>
{
req.session.destroy((err)=>{})
res.send('Thank you! Visit again')
})
app.listen(port,()=>{console.log('Website is running')});

Summary

I hope this article has created a foundation for Session and cookies and its basic usage for a login functionality. Go ahead, try using the same concepts to implement many common scenarios like shopping cart, user preferences etc……..

--

--