Koa IP Filter Middleware

raw JSON →
2.1.4 verified Thu Apr 23 auth: no javascript

The `koa-ip` package provides a robust IP filtering middleware specifically designed for Koa applications. It allows developers to manage network access by configuring either a `whitelist` to permit specific IP addresses or a `blacklist` to deny them. The package accommodates both literal IP strings and regular expressions for defining patterns, enabling flexible control over single IPs, IP ranges, or subnets. Currently stable at version 2.1.4, `koa-ip` exhibits a stable release cadence, typical for well-defined utility middleware, suggesting ongoing maintenance rather than rapid feature development. Its key differentiators include a minimalist API, seamless integration into the Koa middleware chain, and built-in TypeScript definitions, making it easy to adopt in modern Koa projects. By default, it returns a 403 Forbidden status for blacklisted IPs, a behavior that can be customized with an asynchronous handler function, offering fine-grained control over denied requests.

error TypeError: app.use is not a function
cause The Koa application instance (`app`) has not been correctly initialized or is not an instance of Koa.
fix
Ensure you have const Koa = require('koa'); (or import Koa from 'koa';) and const app = new Koa(); at the start of your application file.
error No IP filtering is occurring / Requests are not being blocked
cause This typically happens if `koa-ip` is placed too late in the Koa middleware chain, the IP patterns are incorrect, or `ctx.request.ip` is not accurately reflecting the client's IP (e.g., due to proxy configuration issues).
fix
Verify koa-ip is app.use()d early in your middleware stack. Double-check your whitelist and blacklist patterns. If behind a proxy, ensure app.proxy = true; is configured.
error TypeScript Error: Module '"koa-ip"' has no default export.
cause Attempting to use `import ip from 'koa-ip';` in a TypeScript project where `esModuleInterop` is `false` or `allowSyntheticDefaultImports` is `false` in `tsconfig.json`, and `koa-ip` is a CommonJS module.
fix
Either use the TypeScript-specific CommonJS import: import ip = require('koa-ip'); or enable "esModuleInterop": true and "allowSyntheticDefaultImports": true in your tsconfig.json.
gotcha The order of middleware in Koa is crucial. `koa-ip` should be placed early in the middleware chain to ensure IP filtering occurs before other request handlers or route-matching logic. If placed too late, an unpermitted request might still be processed.
fix Ensure `app.use(ip(...))` is called before other route-handling or request-processing middlewares.
gotcha By default, if an IP matches an entry in the `blacklist` and no custom `handler` function is provided, `koa-ip` will automatically set `ctx.status = 403`. Developers expecting a different default response or behavior must explicitly define a `handler`.
fix Provide a custom `handler` function in the `koa-ip` options object: `{ blacklist: [...], handler: async (ctx, next) => { ctx.status = 401; ctx.body = 'Unauthorized'; } }`
gotcha When `app.proxy` is enabled in Koa (e.g., when behind a load balancer or reverse proxy), `ctx.request.ip` will use the `X-Forwarded-For` header. Ensure `app.proxy = true` is set if relying on forwarded headers, otherwise, `koa-ip` might filter based on the proxy's IP rather than the client's actual IP.
fix If your Koa app is behind a proxy, set `app.proxy = true;` during Koa application initialization to correctly parse client IPs from `X-Forwarded-For`.
gotcha IP patterns using regular expressions or wildcards (`*`) require careful construction. Incorrect patterns can inadvertently block legitimate users or fail to block malicious ones. For CIDR notation (e.g., '192.168.1.0/24'), ensure the library correctly interprets it or convert to appropriate regex if needed (though `koa-ip` supports CIDR directly).
fix Thoroughly test all IP patterns (whitelist and blacklist) to confirm they match intended IP ranges. Use online regex testers for complex regular expressions. Refer to `koa-ip` documentation for supported wildcard syntax and CIDR interpretation.
npm install koa-ip
yarn add koa-ip
pnpm add koa-ip

This example demonstrates how to set up `koa-ip` middleware with both whitelist and blacklist configurations, including a custom handler for blacklisted IPs. It also includes a simulated IP setter for easy local testing of different scenarios.

import Koa from 'koa';
import ip from 'koa-ip';

const app = new Koa();

// Middleware to simulate ctx.request.ip for testing
// In a real application, ctx.request.ip is usually populated by Koa's proxy support or underlying Node.js
app.use(async (ctx, next) => {
  if (ctx.url === '/test-blacklist') {
    ctx.request.ip = '127.0.0.1'; // Simulate a blacklisted IP
  } else if (ctx.url === '/test-whitelist') {
    ctx.request.ip = '192.168.0.50'; // Simulate a whitelisted IP
  } else {
    ctx.request.ip = '203.0.113.1'; // Default IP for other requests
  }
  await next();
});

// Configure koa-ip with both whitelist and a blacklist with a custom handler
app.use(ip({
  whitelist: ['192.168.0.*', /^10\.0\.\d{1,3}\.\d{1,3}$/], // Allow local subnet and 10.0.x.x
  blacklist: ['127.0.0.1', '198.51.100.0/24'], // Deny localhost and a specific CIDR range
  handler: async (ctx) => {
    ctx.status = 403;
    ctx.body = 'Access Denied: Your IP (' + ctx.request.ip + ') is not permitted.';
  }
}));

// This middleware will only be reached if the IP is not blacklisted and matches whitelist (if whitelist is active)
app.use(async (ctx) => {
  ctx.status = 200;
  ctx.body = 'Welcome, your IP (' + ctx.request.ip + ') is allowed!';
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
  console.log('Try visiting these URLs:');
  console.log(`- http://localhost:${PORT}/test-whitelist (should show welcome)`);
  console.log(`- http://localhost:${PORT}/test-blacklist (should show access denied)`);
  console.log(`- http://localhost:${PORT}/ (should show welcome if default IP is not blacklisted)`);
});