Securing APIs in Express: How to Use Rate Limiting and Slow Down Middleware

Public APIs and web applications are frequent targets for abuse—whether from malicious bots, brute-force login attempts, or poorly written clients that unintentionally flood your server. Two of the simplest and most effective protections you can add to an Express application are rate limiting and slow down mechanisms. Used together, they help keep your API responsive, reduce the risk of denial-of-service (DoS) conditions, and protect critical routes like authentication and payment endpoints.


Key Takeaways

  • Rate limiting restricts how many requests a client can make within a time window, preventing abuse and reducing server load.
  • Slow down introduces increasing delays for repeated requests instead of—or in addition to—hard blocking.
  • In Express, libraries such as express-rate-limit and express-slow-down are easy to configure and integrate.
  • Protect sensitive routes (logins, signups, payments, password reset) more aggressively than general public endpoints.
  • Combine rate limiting and slow down with logging, monitoring, and other security measures for a layered defense.

Why Rate Limiting Matters for Your API

Any public-facing API or web application is vulnerable to misuse. Even if your business is small, your endpoints can be probed by automated tools looking for weaknesses. Rate limiting helps you:

  • Prevent brute-force attacks: Limit login attempts from a single IP or user to reduce password-guessing attempts.
  • Protect infrastructure: Stop a small number of clients from consuming a disproportionate amount of resources.
  • Improve cost control: Many hosting environments and third-party services charge based on resource usage. Throttling abusive traffic can lower your bill.
  • Improve user experience: When your API is overwhelmed, all customers suffer. Rate limiting helps maintain a stable, predictable response time.

For small businesses and startups, adding rate limits early in your Express stack is a pragmatic way to raise the security bar without major complexity.


Core Concepts: Rate Limiting vs Slow Down

What Is Rate Limiting?

Rate limiting enforces a maximum number of requests per client over a specified time window. For example:

  • Maximum 100 requests per 15 minutes per IP address.
  • Maximum 5 login attempts per minute for a specific email or username.

When a client exceeds that limit, your server responds with an HTTP status like 429 Too Many Requests, optionally with headers that describe when the client can retry.

This approach is simple and direct: once a client passes the threshold, they are temporarily blocked.

What Is Slow Down?

A slow down mechanism uses delays to discourage excessive requests rather than immediately blocking them. For instance:

  • Allow the first 50 requests quickly.
  • For each request beyond 50, add 500ms of delay.

From the client’s perspective, the API feels slower the more aggressively they hammer it. This can:

  • Reduce the impact of abusive traffic without completely blocking legitimate but bursty usage.
  • Make brute-force attacks less practical by dramatically increasing the time needed to try many combinations.

In practice, rate limiting and slow down are often used together: slow down for mild abuse, followed by hard rate limits for persistent overshoot.


Setting Up Rate Limiting in Express

One of the most popular packages for Express is express-rate-limit. It provides configurable middleware that you can apply to all routes or specific ones.

Install the Package

From your project root, install the dependency:

npm install express-rate-limit

Basic Configuration

Below is a simplified example of applying a global rate limit in an Express app:


const express = require('express');
const rateLimit = require('express-rate-limit');

const app = express();

const apiLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // limit each IP to 100 requests per windowMs
  standardHeaders: true, // Return rate limit info in the RateLimit-* headers
  legacyHeaders: false, // Disable the X-RateLimit-* headers
});

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

app.get('/api/data', (req, res) => {
  res.json({ message: 'Success' });
});

app.listen(3000);

Key configuration options:

  • windowMs: Time frame in milliseconds for the limit (e.g., 15 minutes).
  • max: Maximum number of requests allowed per client in that window.
  • standardHeaders: Adds informative headers like RateLimit-Remaining.
  • message: Optional custom response body when the limit is exceeded.

Protecting Sensitive Routes More Strictly

Not all routes need the same protection. It is common to apply a stricter rate limit to authentication endpoints:


const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // 5 login attempts per 15 minutes per IP
  message: 'Too many login attempts from this IP, please try again later.',
});

app.post('/auth/login', loginLimiter, (req, res) => {
  // handle login
});

This approach lets you tune security where it matters most without degrading performance for low-risk endpoints.


Adding Slow Down to Your Express API

To introduce incremental delays, you can use the express-slow-down package, which is designed to work similarly to express-rate-limit.

Install the Package

npm install express-slow-down

Basic Slow Down Configuration

Here is an example of adding slow down behavior:


const slowDown = require('express-slow-down');

const speedLimiter = slowDown({
  windowMs: 15 * 60 * 1000, // 15 minutes
  delayAfter: 50, // allow 50 requests before delaying responses
  delayMs: 500, // add 500ms per request above delayAfter
});

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

Configuration options to understand:

  • delayAfter: Number of requests allowed in the window before delays kick in.
  • delayMs: How many milliseconds of delay to add for each request above delayAfter.

For example, with delayAfter: 50 and delayMs: 500:

  • Requests 1–50: No delay.
  • Request 51: 500ms delay.
  • Request 52: 1000ms delay.
  • Request 60: 5000ms delay, and so on.

Combining Rate Limit and Slow Down for Better Protection

Rate limiting and slow down are not mutually exclusive. Combining them often yields the best balance between user experience and security.

Layered Example

You might implement:

  • A slow down middleware on all API routes to gently discourage excessive use.
  • A stricter rate limit on sensitive routes (like login or password reset) for stronger protection.

Example:


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

app.post('/auth/login', loginLimiter, (req, res) => {
  // login logic
});

This pattern lets you:

  • Keep general API access flexible and user-friendly.
  • Enforce strong guardrails on routes that are most likely to be targeted by attackers.

Practical Tips and Common Pitfalls

1. Choose the Right Identifier

Most examples use IP addresses to track clients, but that is not always ideal:

  • Shared networks or proxies can make many users appear under a single IP.
  • For authenticated APIs, you may want to rate limit by user ID or API key instead.

Consider what makes sense for your application and your customers to avoid penalizing legitimate use.

2. Consider a Distributed Store

By default, many rate limiting libraries store counters in memory. That is simple, but:

  • It does not share state across multiple server instances.
  • Counters reset when your process restarts.

For production environments, especially when scaling horizontally, use a shared store like Redis so limits apply consistently across all instances.

3. Log and Monitor Violations

Do not just block or delay requests—log when limits are hit. This helps you:

  • Detect ongoing attacks or scraping activity.
  • Adjust your thresholds based on real-world traffic patterns.
  • Identify misbehaving clients or integrations.

4. Communicate Limits to Your Users

If you provide a public API or integrate with partners, document your rate limits. Clear expectations help developers design their clients to be well-behaved, reducing accidental overload and frustration.

5. Combine with Other Security Controls

Rate limiting and slow down are just pieces of the security puzzle. They work best when combined with:

  • Authentication and authorization controls.
  • Input validation and sanitization.
  • HTTPS enforcement.
  • Web application firewalls (WAFs) where appropriate.

Conclusion: Make Rate Limiting a Standard Part of Your Stack

For small businesses and development teams, adding rate limiting and slow down middleware to an Express app is one of the highest-impact, lowest-effort steps you can take to improve API security and reliability. With tools like express-rate-limit and express-slow-down, you can:

  • Protect critical routes from brute-force and abusive traffic.
  • Keep your infrastructure responsive for legitimate users.
  • Scale more confidently as your user base grows.

Start with conservative limits, monitor how your application behaves, and refine your configuration over time. Making these protections a standard part of your Express setup will help you avoid downtime, security incidents, and unpleasant surprises as your app gains traction.


Need Help Hardening and Hosting Your Express App?

If you want support designing, securing, and hosting your Express-based APIs or applications, Izende Studio Web can help—from rate limiting strategies to production-ready environments and monitoring.

Explore Izende Studio Web services to learn how we can support your next project.

Leave a Reply

Your email address will not be published. Required fields are marked *