Secure User Sign In Node Using JWT
Tags: javascript, node, jwt
Published: 2023-03-14 18:34:01

This post will focus on user login in after they have registered. 
You can find the post on user registration [here](https://dev.to/wanguiwaweru/user-registration-in-node-js-a6b).
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](https://auth0.com/docs/secure/tokens/json-web-tokens).

```javascript
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
```
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](https://youtu.be/2RKCDhH6dyA)

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` 

```javascript
const loginRouter = require('./routes/login')
app.use('/api', loginRouter)
```
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c0q7tgaayok86nt0loay.jpg)
Test on Postman using a user you have previously registered. 
![Successful login](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/02204quyedo0slpx371a.jpg)
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0sc0up6j1g20vto5s5hh.jpg)
Code [repo](https://github.com/wanguiwaweru/Authenticate/blob/main/routes/login.js)
Happy coding!!

## References
- [JWT Attaccks](https://portswigger.net/web-security/jwt)
- [Cracking JWT](https://youtu.be/2RKCDhH6dyA)