Lesson 2
Protecting Routes with Middleware
Introduction

In this lesson, we will learn how to protect parts of our To-Do List application using middleware in Express.js. Middleware acts as checkpoints that control access to different routes. By the end of this lesson, you'll understand how to use middleware to enhance the security of your application, much like an office building's security system determines who can access different floors.

What You'll Learn

In this lesson, you'll learn:

  • What middleware is and why it's important.
  • How to set up middleware in Express.js.
  • How to use middleware to protect routes.
  • How to manage sessions for user authentication.
What Is Middleware?

Middleware in Express.js is a series of small programs that handle requests and responses. Imagine middleware as security checkpoints in a building; each checkpoint ensures only authorized individuals can proceed to certain areas.

Middleware can:

  • Execute any code.
  • Modify request and response objects.
  • End the request-response cycle.
  • Move to the next middleware function.

Middleware ensures your application is secure and functions properly by controlling the flow of requests and responses.

Step 1: Setting Up Express.js and MongoDB

Let's set up our Express.js application and connect to MongoDB. This is essential for a running server and a database to store user information.

JavaScript
1const express = require('express'); 2const mongoose = require('mongoose'); 3const session = require('express-session'); 4 5const app = express(); 6const PORT = 3000; 7 8// Connect to MongoDB 9mongoose.connect('mongodb://127.0.0.1:27017/todo-app', { 10 useNewUrlParser: true, 11 useUnifiedTopology: true 12});

Here, we import the necessary libraries, initialize an Express.js application, and connect to a MongoDB database named todo-app. Connecting to MongoDB is crucial for storing user data and managing user authentication.

Step 2: Setting Up Session Middleware

Sessions help track user information as they navigate through the app, similar to how an office maintains visitor logs.

JavaScript
1// Middleware for sessions 2app.use(session({ 3 secret: 'your-secret-key', 4 resave: false, 5 saveUninitialized: true 6}));

In this step, we use the express-session middleware to manage sessions. We configure the session with a secret key to sign the session ID cookie, which helps prevent tampering. The resave option, set to false, ensures the session is not saved back to the session store unless it has been modified. The saveUninitialized option, set to true, saves new but unmodified sessions to the store. This setup allows the application to maintain state across multiple requests, essential for tracking logged-in users.

Step 3: Creating the Authenticate Middleware

Let’s create our custom middleware function to check if a user is logged in. This function will act as a security checkpoint to protect sensitive routes.

JavaScript
1// Middleware to check if the user is logged in 2const authenticateUser = (req, res, next) => { 3 if (!req.session.user) return res.status(401).json({ message: 'Access denied' }); 4 next(); 5};

Here, we define a middleware function called authenticateUser. The function checks if req.session.user exists, which stores data specific to the logged-in user. If the user is not logged in, it returns a 401 status (Unauthorized) with an "Access denied" message. If the user is logged in, it calls the next() function to proceed.

Step 4: Handling User Login

We need a route to handle user login. This route will check the user's credentials and create a session upon successful login.

JavaScript
1// Simple user database simulation 2const users = { 3 'testuser': 'testpassword' 4}; 5 6// Login route 7app.post('/login', (req, res) => { 8 const { username, password } = req.body; // req.body contains the data sent in the request 9 if (users[username] && users[username] === password) { 10 req.session.user = username; // Save user in session 11 res.json({ message: 'Login successful' }); 12 } else { 13 res.status(401).json({ message: 'Invalid username or password' }); 14 } 15});

In this part, we simulate a simple user database with an object. The /login route accepts a POST request with username and password. If the credentials match, it saves the user in the session and returns a success message. Otherwise, it returns an error message. Handling user login is essential for managing access to your application, which will allow us to protect specific routes.

Step 5: Protecting Routes with Middleware

Let's create a protected route that only logged-in users can access. We'll use our authenticateUser middleware to guard this route.

JavaScript
1// Route to handle protected route 2app.get('/protected', authenticateUser, (req, res) => { 3 res.send('This is a protected route'); 4});

Here, we create a protected route /protected and use the authenticateUser middleware before the route handler. If the user is authenticated, it shows the message "This is a protected route"; otherwise, it returns "Access denied". Protecting routes ensures only authorized users can access sensitive parts of your application.

Conclusion

In this lesson, we learned how to protect routes in an Express.js application using middleware. We set up sessions, created an authenticateUser middleware, and handled user login to manage access to a protected route.

Practice exercises are essential to reinforce what you've learned. By protecting routes, you ensure that only authorized users can access sensitive parts of your application, making it more secure. Now, let's practice.

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.