Secure User Sign In Node Using JWT

wanguiwaweru

Bernice Waweru

Posted on March 14, 2023

Secure User Sign In Node Using JWT

This post will focus on user login in after they have registered.
You can find the post on user registration here.
In the previous section, we created the server, connected to MongoDB and also created the user model.
Here we will build up on the login logic.

Create login.js inside the routes folder.
Inside this file we will create the login endpoint which will:

  • Receive user details from client request.
  • Validate the details provided.
  • Check if the user exists in the database.
  • Authenticate the user by comparing the details provided and those in the database.
  • Return a Json Web Token to the client which will be used to authenticate the user in future requests.

The token is returned as a cookie.

Explore more on Json Web Tokens and how to use them here.

require('dotenv').config()
const { User, validate } = require('../models/user')
const bcrypt = require('bcrypt')
const express = require('express')
const jwt = require('jsonwebtoken')
const router = express.Router()
const SECRET = process.env.SECRET
const jwtExpirySeconds = 300

const loginRouter = router.post('/login', async (req, res) => {
    const { error } = validate(req.body)
    if (error) {
        return res.status(401).send(error.details[0].message)
    } else {
        try {
            let user = await User.findOne({ email: req.body.email })
            if (!user) {
                return res.status(400).json({ message: 'Incorrect email or password.' })
            }
            const correctPassword = await bcrypt.compare(req.body.password, user.password)
            if (!correctPassword) {
                return res.status(400).json({ message: 'Incorrect email or password.' })
            }
            const token = jwt.sign({ id: user._id }, SECRET)
            res.cookie(
                "token", token, {
                httpOnly: true,
                secure: process.env.NODE_ENV !== 'development',
                sameSite: "strict",
                maxAge: jwtExpirySeconds * 1000
            })
            res.json({ message: 'Successfully logged in' })

        } catch (err) {
            return res.status(400).json({ message: err.message })
        }
    }
})

module.exports = loginRouter
Enter fullscreen mode Exit fullscreen mode

Let us understand what happens with the Json Web Tokens.
You need to set a SECRET on the .env file which will be used to sign the token

Ensure the SECRET is not easily predictable because it can be used to exploit the JWT tokens. Here is an example

After generating the JWT token we set it in the cookie which will be sent to the client.

Add the following changes to index.js

const loginRouter = require('./routes/login')
app.use('/api', loginRouter)
Enter fullscreen mode Exit fullscreen mode

This ensure the application calls the loginRouter callback function when the application receives requests that match the specified route(api/login) and method(post).

Run the application using node index.js

Server start up
Test on Postman using a user you have previously registered.
Successful login
On the the cookies tab the HttpOnly flag is set to true and the secure flag is set to false because this is still in development.
When in production we can set this flag to true.

Cookie data
Code repo
Happy coding!!

References

πŸ’– πŸ’ͺ πŸ™… 🚩
wanguiwaweru
Bernice Waweru

Posted on March 14, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Secure User Sign In Node Using JWT
javascript Secure User Sign In Node Using JWT

March 14, 2023

Node.js API Authentication 😍
javascript Node.js API Authentication 😍

February 9, 2021

JWT Authentication Best Practices
javascript JWT Authentication Best Practices

December 4, 2020