Skip to content

rrd108/nuxt-api-shield

Folders and files

NameName
Last commit message
Last commit date
Sep 10, 2024
Sep 12, 2024
Dec 4, 2024
Dec 4, 2024
Mar 29, 2024
Mar 29, 2024
Mar 30, 2024
Mar 29, 2024
Sep 21, 2024
Oct 23, 2024
Sep 12, 2024
Nov 21, 2024
Sep 10, 2024
Mar 29, 2024
Dec 13, 2024

Repository files navigation

Nuxt API Shield

npm version npm downloads License Nuxt

This Nuxt module implements a rate limiting middleware to protect your API endpoints from excessive requests.

Features

  • IP-Based Rate limiting and Brute Force Protection
    • Tracks and enforces rate limits for individual IP addresses.
    • Prevents malicious actors or excessive requests from a single source from overwhelming your API.
  • Customizable Rate Limits
    • Configure maximum request count, duration within which the limit applies, and a ban period for exceeding the limit.
    • Add a delay to responses when a user is banned to discourage further abuse.
    • Customize the error message for banned users.
    • Optionally include the Retry-After header in responses when a user is banned.
    • Tailor the rate-limiting behavior to align with your API's specific needs and usage patterns.
  • Event-Driven Handling
    • Intercepts incoming API requests efficiently using Nuxt's event system.
    • Ensures seamless integration with your Nuxt application's request lifecycle.
  • Flexible Storage
    • Utilizes Nuxt's unstorage abstraction for versatile storage options.
    • Store rate-limiting data in various storage providers (filesystem, memory, databases, etc.) based on your project's requirements.
  • Configurable with Runtime Config
    • Easily adjust rate-limiting parameters without code changes.
    • Adapt to dynamic needs and maintain control over rate-limiting behavior through Nuxt's runtime configuration.
  • Clear Error Handling
    • Returns a standardized 429 "Too Many Requests" error response when rate limits are exceeded.
    • Facilitates proper error handling in client-side applications for a smooth user experience.

Quick Setup

1. Add nuxt-api-shield dependency to your project

# Using pnpm
pnpm add nuxt-api-shield

# Using yarn
yarn add nuxt-api-shield

# Using npm
npm install nuxt-api-shield

2. Add nuxt-api-shield to the modules section of nuxt.config.ts

You should add only the values you want to use differently from the default values.

export default defineNuxtConfig({
  modules: ["nuxt-api-shield"],
  nuxtApiShield: {
    /*limit: {
      max: 12,        // maximum requests per duration time, default is 12/duration
      duration: 108,   // duration time in seconds, default is 108 seconds
      ban: 3600,      // ban time in seconds, default is 3600 seconds = 1 hour
    },
    delayOnBan: true  // delay every response with +1sec when the user is banned, default is true
    errorMessage: "Too Many Requests",  // error message when the user is banned, default is "Too Many Requests"
    retryAfterHeader: false, // when the user is banned add the Retry-After header to the response, default is false
    log: {
      path: "logs", // path to the log file, every day a new log file will be created, use "" to disable logging
      attempts: 100,    // if an IP reach 100 requests, all the requests will be logged, can be used for further analysis or blocking for example with fail2ban, use 0 to disable logging
    },
    routes: [], // specify routes to apply rate limiting to, default is an empty array meaning all routes are protected.
    // Example:
    // routes: ["/api/v2/", "/api/v3/"], // /api/v1 will not be protected, /api/v2/ and /api/v3/ will be protected */
  },
});

3. Add nitro/storage to nuxt.config.ts

You can use any storage you want, but you have to use shield as the name of the storage.

{
  "nitro": {
    "storage": {
      "shield": {
        // storage name, you **must** use "shield" as the name
        "driver": "memory"
      }
    }
  }
}

If you use for example redis, you can use the following configuration, define the host and port.

{
  "nitro": {
    "storage": {
      "shield": {
        "driver": "redis",
        "host": "localhost",
        "port": 6379,
      }
    }
  }
}

4. Add shield:clean to nuxt.config.ts

{
  "nitro": {
    "experimental": {
      "tasks": true
    },
    "scheduledTasks": {
      "*/15 * * * *": ["shield:clean"] // clean the shield storage every 15 minutes
    }
  }
}

5. Create your clean task

In server/tasks/shield/clean.ts you should have something like this.

import type { RateLimit } from "#imports";

export default defineTask({
  meta: {
    description: "Clean expired bans",
  },
  async run() {
    const shieldStorage = useStorage("shield");

    const keys = await shieldStorage.getKeys();
    keys.forEach(async (key) => {
      const rateLimit = (await shieldStorage.getItem(key)) as RateLimit;
      if (isBanExpired(rateLimit)) {
        await shieldStorage.removeItem(key);
      }
    });
    return { result: keys };
  },
});

Development

# Install dependencies
yarn

# Generate type stubs
yarn dev:prepare

# Develop with the playground
yarn dev

# Build the playground
yarn dev:build

# Run ESLint
yarn lint

# Run Vitest
yarn test
yarn test:watch

# Release new version
yarn release:patch
yarn release:minor