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.
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
.
- On initialisation, it checks the
req
object for any cookies with the name‘uniqueSessionID’
. - If it finds one, it will look up the value of the
‘uniqueSessionID’
in the store and populate thereq.session
object. - 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 newreq.session
object but does not save it in the store unless changed.(saveUninitialized:false)
- If the data (
req.session
object) is changed, it gets saved to the store and a cookie will be created in theres
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.
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.
req.session
object is populated (loggedIn
andusername
properties) and saved in the store.- A cookie is created and passed into the response in the Header:
Set-Cookie:uniqueSessionID=s%3AiGn4lXP-Jhf6RahxDYQHgnCWTvq8C7u4.1YPir9YmqXlhLJXDSQb%2Fdw7PwR6EOQWAgwZP7O%2BZ7XQ; Path=/; HttpOnly
- All subsequent requests will have the cookie value and its corresponding
req.session
object in the store. - The above session data will now be accessible by the other routes
localhost:3000
andlocalhost: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……..