2-how-to-set-up-a-secure-expressjs-api-with-jwt-authentication.html

How to Set Up a Secure Express.js API with JWT Authentication

In the world of web development, creating secure APIs is paramount. With the rise of modern web applications, implementing robust authentication mechanisms is essential to protect user data and maintain the integrity of your application. In this guide, we will explore how to set up a secure Express.js API with JSON Web Token (JWT) authentication.

What is Express.js?

Express.js is a fast, unopinionated, minimalist web framework for Node.js. It provides a robust set of features for web and mobile applications, allowing developers to build APIs quickly and efficiently. Its simplicity and flexibility make it a favorite for building server-side applications.

What is JWT?

JSON Web Token (JWT) is 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.

Why Use JWT for Authentication?

  • Stateless: JWTs do not require session storage on the server, making them scalable.
  • Compact: The token is small in size, which is ideal for mobile applications.
  • Self-contained: It contains all the information needed for authentication, reducing database lookups.

Use Cases for Express.js and JWT

  • Single Page Applications (SPAs): Securely authenticate users when they access your app.
  • Mobile Applications: Provide a seamless authentication experience for users on mobile devices.
  • Microservices: Facilitate secure communication between various services within an architecture.

Setting Up Your Express.js API with JWT Authentication

Let’s walk through the steps to create a simple Express.js API that uses JWT for authentication.

Step 1: Initialize Your Project

Begin by creating a new directory for your project and navigating into it:

mkdir express-jwt-api
cd express-jwt-api

Now, initialize a new Node.js project:

npm init -y

Step 2: Install Dependencies

You will need to install the following packages:

  • express: The web framework.
  • jsonwebtoken: A library to sign and verify JWTs.
  • bcryptjs: A library to hash passwords.
  • dotenv: For environment variable management.

Install these by running:

npm install express jsonwebtoken bcryptjs dotenv

Step 3: Set Up Your Server

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

// server.js
const express = require('express');
const bodyParser = require('body-parser');
const dotenv = require('dotenv');

dotenv.config();

const app = express();
const PORT = process.env.PORT || 3000;

app.use(bodyParser.json());

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

Step 4: Create User Registration and Login Endpoints

We'll create two endpoints: one for user registration and another for login.

User Registration

Create a new file named auth.js for handling authentication logic:

// auth.js
const express = require('express');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');

const router = express.Router();
let users = []; // In-memory user storage (for demonstration)

router.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);
    users.push({ username, password: hashedPassword });

    res.status(201).send('User registered successfully');
});

User Login

Add the login endpoint to auth.js:

router.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 credentials');
    }

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

module.exports = router;

Step 5: Integrate the Authentication Routes

Back in your server.js, import the authentication routes and use them:

const authRoutes = require('./auth');

app.use('/api', authRoutes);

Step 6: Protecting Routes with JWT Middleware

Now, let’s create middleware to protect certain routes. Create a new file named middleware.js:

// middleware.js
const jwt = require('jsonwebtoken');

const authenticateToken = (req, res, next) => {
    const token = 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();
    });
};

module.exports = authenticateToken;

Step 7: Protecting a Sample Route

In server.js, create a sample protected route:

const authenticateToken = require('./middleware');

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

Step 8: Testing the API

You can test your API using tools like Postman or Insomnia.

  1. Register a User:
  2. POST to /api/register with body { "username": "testuser", "password": "password123" }

  3. Login to Get a Token:

  4. POST to /api/login with body { "username": "testuser", "password": "password123" }

  5. Access Protected Route:

  6. GET /api/protected with the Authorization header set to Bearer YOUR_TOKEN_HERE

Conclusion

By following these steps, you have successfully set up a secure Express.js API with JWT authentication. This setup allows you to authenticate users, protect routes, and ensure that your application's data remains secure. As you expand your API, consider implementing additional features like user roles, password reset functionality, and more robust error handling to enhance your application's security and user experience.

Remember, security is an ongoing process, so stay updated on best practices and continuously improve your application's defenses. 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.