Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.lintliot.com/llms.txt

Use this file to discover all available pages before exploring further.

The Koa adapter provides a middleware function you mount on your Koa application before your router. It intercepts every request, runs WAF, bot detection, rate limiting, and anomaly detection, then attaches a lintliot context object to ctx.state for downstream middleware and route handlers.

Prerequisites

  • Koa 2 with async middleware support.
  • @lintliot/sdk installed. See Install the LintLiot SDK.
  • LINTLIOT_API_KEY set in your environment.

Basic setup

1

Create a Lintliot instance

Import createLintliot and initialize it once at the module level.
import { createLintliot } from '@lintliot/sdk'

const lintliot = createLintliot({
  apiKey: process.env.LINTLIOT_API_KEY!,
})
2

Mount the middleware before your router

Import createKoaMiddleware and mount it with app.use before your router:
import Koa from 'koa'
import Router from '@koa/router'
import { createLintliot } from '@lintliot/sdk'
import { createKoaMiddleware } from '@lintliot/sdk/koa'

const app = new Koa()
const router = new Router()
const lintliot = createLintliot({ apiKey: process.env.LINTLIOT_API_KEY! })

// Mount before the router
app.use(createKoaMiddleware(lintliot))

router.get('/api/users', async (ctx) => {
  ctx.body = { users: [] }
})

app.use(router.routes())
app.listen(3000)
createKoaMiddleware must be mounted before your router. If you mount it after router.routes(), incoming requests reach your route handlers before LintLiot inspects them.

Configure middleware options

Pass options to customize protection behavior and enable security headers:
app.use(createKoaMiddleware(lintliot, {
  rateLimit: { max: 200, windowMs: 60_000 },
  waf: 'block',
  securityHeaders: true,
  skipRoutes: ['/health', '/metrics'],
}))
Setting securityHeaders: true adds CSP, HSTS, X-Frame-Options, Referrer-Policy, and other headers to every passing response via ctx.set.

One-line setup

If you prefer not to manage the lintliot instance directly, use lintliotKoa. It handles instance caching internally:
import Koa from 'koa'
import { lintliotKoa } from '@lintliot/sdk/koa'

const app = new Koa()

app.use(lintliotKoa({ apiKey: process.env.LINTLIOT_API_KEY! }))

Access LintLiot context in handlers

After the middleware runs, ctx.state.lintliot contains the resolved IP address and user ID:
router.get('/api/profile', async (ctx) => {
  const { ip, userId } = ctx.state.lintliot
  ctx.body = { ip, userId }
})
The user ID is extracted from ctx.state.userId, ctx.state.auth.userId (Clerk), ctx.state.user.id (Passport), ctx.state.user.sub (Auth0), or the x-user-id request header.

Per-route permission guards

Use koaCan to require a permission on a specific route. Add it as a router middleware before your handler:
import { koaCan } from '@lintliot/sdk/koa'

// Single permission
router.delete('/api/users/:id', koaCan(lintliot, 'users:delete'), deleteUserHandler)

// Multiple permissions (all must pass)
router.post('/api/admin', koaCan(lintliot, 'admin:write', 'billing:manage'), adminHandler)
If the request carries no user ID, koaCan returns 401. If the user lacks the required permission, it returns 403.

Per-route rate limiting

Use koaRateLimit to apply a stricter limit to a specific route:
import { koaRateLimit } from '@lintliot/sdk/koa'

router.post(
  '/api/auth/login',
  koaRateLimit(lintliot, { max: 5, windowMs: 60_000 }),
  loginHandler
)
The global middleware already enforces a baseline rate limit on all routes. koaRateLimit is for endpoints that need a tighter threshold, like login, password reset, or OTP generation.

Register routes for pentest discovery

After all your router definitions, call registerKoaRoutes to send the route list to the LintLiot Pentest Engine:
import { registerKoaRoutes } from '@lintliot/sdk/koa'

// Define routes first
router.get('/api/users', usersHandler)
router.post('/api/login', loginHandler)

// Then register them (fire-and-forget)
registerKoaRoutes(lintliot, router)
Route registration is asynchronous, retries once on failure, and never blocks request handling.