Bot Detection

IP validation, the bot detection middleware, how fingerprints are forwarded to the IAM service check endpoint, and firewall-level banning with UFW.

The module integrates with the Bot Detector pipeline running inside the IAM service. The gateway extracts the visitor fingerprint from each request and forwards it to the IAM service, which runs it through the full detection pipeline. Flagged visitors receive a 403 response at the gateway level. On Linux servers with UFW installed, banned IPs can be blocked at the firewall.


Global middleware

The bot detection chain is wired as three separate global middlewares that run in order: isIPValid, botDetectorMiddleware, and generateCsrfCookie. Register them on your H3 app or Nitro instance as shown in the H3 or Nitro setup. When using the Nuxt module with enableMiddleware: true, the chain is registered automatically. The bot detection call happens before the CSRF cookie is issued, so flagged visitors never receive a valid session token.

The bot detector in this module should be enabled by default, disabling it while using the IAM service will fail session rotation and verification.

The middleware skips processing for:

  • HEAD requests
  • The /api/health path
  • Framework internal paths starting with /_nuxt or /api/_mdc (only relevant under Nuxt)
  • Requests with X-Forwarded-For: 127.0.0.1 or ::1 (loopback, trusted internal traffic)

isIPValid

isIPValid extracts the client IP address from the request headers and validates it with net.isIP(). This function does not make a network call. It runs as the first step of the middleware chain so that any request with an invalid or missing IP is rejected immediately with HTTP 403, before botDetectorMiddleware runs.


botDetectorMiddleware

botDetectorMiddleware forwards the visitor fingerprint to the IAM service /check endpoint. The IAM service runs the full Bot Detector pipeline and returns a bot score. When the score exceeds the ban threshold, the middleware throws HTTP 403.

// The middleware is called automatically in the global middleware chain.
// To run it manually on a specific route:
export default defineEventHandler(async (event) => {
  isIPValid(event)
  await botDetectorMiddleware(event)
  // Proceed only if the visitor is not flagged
})

On the first request from a visitor, the middleware calls /check and sets __Host-dr_i_n, a signed host-only cookie that tracks the result. On subsequent requests where both __Host-dr_i_n and the canary_id cookie (issued by the IAM service) are present and the __Host-dr_i_n signature is valid, the middleware skips the IAM call and returns immediately. This avoids calling the full bot detection pipeline on every page view.

The __Host-dr_i_n cookie is HMAC-signed using cryptoCookiesSecret and set with HttpOnly: true, SameSite: Strict, Secure: true, and a 2-hour TTL. If the signature verification fails for any reason, the middleware returns HTTP 403 with code CANARY_TEMPERING.

Bot detection is also skipped for static assets such as CSS, images, and font files, and for OAuth redirect routes.

When enableFireWallBans is true in the configuration and the visitor is flagged, banIp is called to add a UFW rule blocking the IP at the OS level.

enableFireWallBans requires a Linux environment with ufw installed and passwordless sudo configured for the Node.js process. Do not enable this on serverless or edge environments such as Vercel, Netlify, or Cloudflare Workers.

checkForBots

checkForBots is a low-level helper that calls the IAM /check endpoint with a prepared signed cookie and visitor context. It is used internally by botDetectorMiddleware and is exported for cases where you need to run the check with explicit control over the cookie and method, for example when building a custom middleware chain.

import { crypto } from 'node:crypto'
import { checkForBots, getLogger, createSignedValue } from 'auth-h3client/v2'

const log = getLogger().child({ service: 'api' })
const uuid = crypto.randomBytes(32).toString('hex')
const cookieValue = createSignedValue(uuid, 1000 * 60 * 60 * 2, 'normal')

await checkForBots(
  { name: '__Host-dr_i_n', value: cookieValue },
  event,
  event.req.method,
  log,
  config.enableFireWallBans,
  getCookie(event, 'canary_id')
)

The function throws HTTP 403 when the IAM service flags the visitor, and HTTP 502 when the IAM service is unreachable. On success it sets the __Host-dr_i_n cookie on the response and stores the tracking result in event.context.trackingResult.

For most cases, use botDetectorMiddleware directly rather than calling this function: it handles cookie generation, deduplication, and the skip logic automatically.


banIp

banIp(ip) executes a sudo ufw insert 1 deny from <ip> to any command to block the IP at the firewall level. It is called automatically by botDetectorMiddleware when enableFireWallBans is true and the visitor score exceeds the threshold.

Call it directly when implementing custom ban logic:

await banIp(clientIp)

The firewall rule persists across application restarts. Managing and reviewing the rules is outside the scope of this module. UFW rules can be listed with sudo ufw status numbered and removed with sudo ufw delete <rule_number>.


Bot detection in the IAM service

The full detection pipeline with 17 configurable checkers, scoring logic, canary cookie fingerprinting, and good-bot exemptions runs inside the IAM service via the Bot Detector integration. See Bot Detection for complete coverage of the pipeline and how to configure individual checkers.

Logo