Secure User Sign In Node Using JWT
Bernice Waweru
Posted on March 14, 2023
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
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)
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
Test on Postman using a user you have previously registered.
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.
Code repo
Happy coding!!
References
Posted on March 14, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.