how-to-implement-a-login-system-with-jwt-in-nodejs.html

How to Implement a Login System with JWT in Node.js

In today's digital world, securing user data is paramount. Implementing a login system is one of the first steps in protecting sensitive information. JSON Web Tokens (JWT) have emerged as a popular method for handling authentication in web applications. In this article, we’ll walk through the process of creating a login system using JWT in Node.js, covering everything from setup to deployment.

What is JWT?

JSON Web Tokens (JWT) are an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs are commonly used for authentication and information exchange.

Key Features of JWT

  • Compact: JWTs can be sent via URL, POST parameters, or inside an HTTP header.
  • Self-contained: They contain all the necessary information about the user, eliminating the need for database lookups.
  • Secure: Can be signed using a secret (HMAC algorithm) or a public/private key pair using RSA or ECDSA.

Use Cases for JWT

  • Authentication: Instead of sending username and password with each request, send a JWT token.
  • Information Exchange: Securely transmit information between parties.
  • Single Sign-On (SSO): Allow users to authenticate once and gain access to multiple applications.

Setting Up Your Node.js Project

To start, ensure you have Node.js and npm installed. Create a new directory for your project and initialize it.

mkdir jwt-login-system
cd jwt-login-system
npm init -y

Next, install the necessary packages:

npm install express jsonwebtoken bcryptjs dotenv
  • Express: A web framework for Node.js.
  • jsonwebtoken: A library to work with JWT.
  • bcryptjs: For hashing passwords.
  • dotenv: To manage environment variables.

Creating the Basic Server

Create a new file named server.js and set up a basic Express server.

// server.js
const express = require('express');
const dotenv = require('dotenv');

dotenv.config();
const app = express();
const PORT = process.env.PORT || 5000;

app.use(express.json());

app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

User Registration

Next, let's implement user registration, where we will hash the password before storing it.

User Model

For simplicity, we'll use an in-memory array to store users instead of a database.

// Mock database
let users = [];

Registration Endpoint

Add a registration endpoint to server.js:

app.post('/register', async (req, res) => {
  const { username, password } = req.body;

  // Check if user already exists
  const existingUser = users.find(user => user.username === username);
  if (existingUser) {
    return res.status(400).send('User already exists');
  }

  // Hash the password
  const hashedPassword = await bcrypt.hash(password, 10);

  // Store the user
  users.push({ username, password: hashedPassword });
  res.status(201).send('User registered successfully');
});

User Login

Now let's create a login endpoint that generates a JWT token upon successful authentication.

Login Endpoint

Add the following code to handle user login:

app.post('/login', async (req, res) => {
  const { username, password } = req.body;
  const user = users.find(user => user.username === username);

  if (!user || !(await bcrypt.compare(password, user.password))) {
    return res.status(401).send('Invalid username or password');
  }

  // Generate JWT
  const token = jwt.sign({ username: user.username }, process.env.JWT_SECRET, { expiresIn: '1h' });
  res.json({ token });
});

Securing Endpoints with JWT

Now we need to create middleware to protect certain routes by verifying the JWT.

Middleware for Authentication

Add the following middleware function:

function authenticateToken(req, res, next) {
  const token = req.headers['authorization'] && req.headers['authorization'].split(' ')[1];
  if (!token) return res.sendStatus(401);

  jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
    if (err) return res.sendStatus(403);
    req.user = user;
    next();
  });
}

Protected Route

Create a protected route that requires a valid JWT:

app.get('/protected', authenticateToken, (req, res) => {
  res.send(`Hello ${req.user.username}, you have access to this protected route`);
});

Testing the API

You can use tools like Postman or Insomnia to test your API:

  1. Register a new user by sending a POST request to /register.
  2. Login to receive a JWT by sending a POST request to /login.
  3. Access the protected route by including the JWT in the Authorization header.

Conclusion

Implementing a JWT-based login system in Node.js is a powerful way to secure your web applications. With the steps outlined in this guide, you should have a reliable authentication system that can easily be extended and integrated into your projects.

JWTs not only enhance security but also improve user experience by allowing session persistence without the need for constant database checks. As you build more complex applications, consider incorporating additional features such as token expiration, refresh tokens, and more robust user management.

Happy coding!

SR
Syed
Rizwan

About the Author

Syed Rizwan is a Machine Learning Engineer with 5 years of experience in AI, IoT, and Industrial Automation.