DEV Community

Bernice Waweru
Bernice Waweru

Posted on

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

Top comments (0)