How to Secure Your Koa App with SecureNow — Full-Stack Observability for Node.js APIs
Complete walkthrough for adding security monitoring to your Koa.js API with the securenow npm package. Covers CLI login, free trial setup, body capture, PM2 deployment, Docker, and trace verification.

How to Secure Your Koa App with SecureNow — Full-Stack Observability for Node.js APIs
Koa gives you a minimal, expressive foundation for building APIs — but once you are serving real traffic, you need more than elegant middleware composition. You need to know what requests are hitting your routes, whether they are benign, and how your service behaves under pressure.
SecureNow plugs into your Koa application at the Node.js runtime level, capturing every HTTP request as an OpenTelemetry trace. Those traces feed a security analysis engine that surfaces SQL injection attempts, credential stuffing, API abuse, and anomalous traffic patterns — all without adding a single line of middleware.
This guide walks you through the full setup: installing the package, authenticating with the CLI, creating an application on the free trial, configuring environment variables, instrumenting your Koa app (with full body capture), and deploying to production.
Prerequisites
- Node.js 18+ installed
- An existing Koa project with
koa-bodyparser(or willingness to scaffold one) - A terminal and a browser
No SecureNow account yet? The CLI handles signup for you.
Step 1: Install the Package
From your project directory:
npm install securenow
This single package includes the OpenTelemetry SDK, auto-instrumentations for Node.js, an OTLP exporter, the SecureNow CLI, and optional console-log forwarding. Koa and its ecosystem packages should already be in your project.
Step 2: Log In via the CLI
Authenticate with SecureNow:
npx securenow login
A browser tab opens at app.securenow.ai where you can sign up or log in. The token is saved to ~/.securenow/credentials.json and authorizes all subsequent CLI commands.
Prefer a non-interactive flow? Generate a CLI token from your dashboard at Settings → CLI Token, then run:
npx securenow login --token YOUR_TOKEN
Verify you are logged in:
npx securenow whoami
Step 3: Create an Application (Free Trial)
Every monitored application gets a unique identifier (the app key). Create one:
npx securenow apps create my-koa-api
When prompted to pick a ClickHouse instance, choose Free Trial — this gives you a managed OTLP collector at https://freetrial.securenow.ai:4318 at no cost and with no credit card.
After creation:
✔ Application created
SECURENOW_APPID=c3d4e5f6-a7b8-9012-3456-789abcdef012
SECURENOW_INSTANCE=https://freetrial.securenow.ai:4318
Add these to your .env file.
Set the new app as your default:
npx securenow config set defaultApp c3d4e5f6-a7b8-9012-3456-789abcdef012
Step 4: Configure Environment Variables
Create (or update) a .env file in your project root:
SECURENOW_APPID=c3d4e5f6-a7b8-9012-3456-789abcdef012
SECURENOW_INSTANCE=https://freetrial.securenow.ai:4318
SECURENOW_LOGGING_ENABLED=1
SECURENOW_CAPTURE_BODY=1
| Variable | Purpose |
|---|---|
SECURENOW_APPID | Identifies your app in the dashboard. Use the key from Step 3. |
SECURENOW_INSTANCE | OTLP collector URL. Free trial default shown above. |
SECURENOW_LOGGING_ENABLED | Set to 1 to forward console.log/warn/error as OTel logs. |
SECURENOW_CAPTURE_BODY | Set to 1 to attach request bodies to trace spans. Koa with koa-bodyparser supports this fully. Sensitive fields are automatically redacted. |
Step 5: Instrument Your Koa App
You have two options — pick whichever fits your workflow.
Option A: Require at the Top of Your Entry File (Recommended)
Add require('securenow/register') as the very first line of your entry file, before any other imports:
require('securenow/register');
require('securenow/console-instrumentation');
const Koa = require('koa');
const Router = require('@koa/router');
const bodyParser = require('koa-bodyparser');
const app = new Koa();
const router = new Router();
app.use(bodyParser());
router.get('/health', (ctx) => {
ctx.body = { status: 'ok', timestamp: new Date().toISOString() };
});
router.post('/tasks', (ctx) => {
const { title, description, priority } = ctx.request.body;
if (!title) {
ctx.status = 400;
ctx.body = { error: 'title is required' };
return;
}
const task = { id: Date.now(), title, description, priority, createdAt: new Date().toISOString() };
ctx.status = 201;
ctx.body = task;
});
app.use(router.routes());
app.use(router.allowedMethods());
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Koa server running on port ${PORT}`);
});
securenow/register starts the OpenTelemetry SDK, reads your .env, and auto-instruments HTTP, Koa, @koa/router, database drivers, and more. securenow/console-instrumentation forwards console.* calls as OTel log records so they appear alongside your traces.
Option B: Zero Code Changes with the Preload Flag
If you prefer not to modify your source code, preload the modules via Node's -r flag:
node -r securenow/register -r securenow/console-instrumentation app.js
Or in your package.json:
{
"scripts": {
"start": "node app.js",
"start:observe": "node -r securenow/register -r securenow/console-instrumentation app.js"
}
}
Step 6: Start and Verify
Run your app:
node app.js
You should see confirmation in your terminal:
[securenow] OTel SDK started → https://freetrial.securenow.ai:4318/v1/traces
[securenow] 📋 Logging: ENABLED → https://freetrial.securenow.ai:4318/v1/logs
[securenow] Console instrumentation installed
Koa server running on port 3000
Generate some traffic:
curl http://localhost:3000/health
curl -X POST http://localhost:3000/tasks -H "Content-Type: application/json" -d '{"title":"Review PR","priority":"high"}'
Then check your dashboard:
npx securenow status
Your app should appear as protected. Browse traces from the terminal:
npx securenow traces
Or open app.securenow.ai to explore traces, logs, security issues, and analytics.
Bonus: Useful CLI Commands
Once your app is instrumented, the CLI becomes your terminal-based control plane:
| Command | What It Does |
|---|---|
securenow traces | List recent traces |
securenow traces show <traceId> | Inspect a single trace |
securenow traces analyze <traceId> | AI-powered trace analysis |
securenow logs | List recent logs |
securenow issues | View detected security issues |
securenow analytics | Traffic and performance analytics |
securenow ip <address> | Look up an IP address |
securenow blocklist add <ip> | Block a malicious IP |
securenow alerts rules | Manage alert rules |
securenow forensics | Run natural-language forensic queries |
Production Deployment with PM2
For production, use PM2 with an ecosystem config:
// ecosystem.config.js
module.exports = {
apps: [{
name: 'my-koa-api',
script: './app.js',
instances: 4,
exec_mode: 'cluster',
node_args: '-r securenow/register -r securenow/console-instrumentation',
env: {
SECURENOW_APPID: 'c3d4e5f6-a7b8-9012-3456-789abcdef012',
SECURENOW_INSTANCE: 'https://freetrial.securenow.ai:4318',
SECURENOW_LOGGING_ENABLED: '1',
SECURENOW_CAPTURE_BODY: '1',
SECURENOW_NO_UUID: '1',
NODE_ENV: 'production',
}
}]
};
pm2 start ecosystem.config.js
Setting SECURENOW_NO_UUID=1 ensures all cluster workers report under the same service name.
Docker Deployment
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
ENV SECURENOW_APPID=my-koa-api
ENV SECURENOW_INSTANCE=https://freetrial.securenow.ai:4318
ENV SECURENOW_LOGGING_ENABLED=1
ENV SECURENOW_CAPTURE_BODY=1
ENV NODE_ENV=production
EXPOSE 3000
CMD ["node", "app.js"]
If you used Option B (preload flag), update the CMD:
CMD ["node", "-r", "securenow/register", "-r", "securenow/console-instrumentation", "app.js"]
What SecureNow Detects Automatically
Once traces are flowing, SecureNow watches for:
- SQL injection — malicious patterns in query parameters and request bodies
- XSS attempts — script injection in user input
- Credential stuffing — high-velocity failed authentication attempts
- API abuse — unusual request patterns, rate-limit evasion, unauthorized endpoint access
- Anomalous traffic — AI-powered detection of behavioral outliers
- Supply-chain signals — unexpected outbound calls from your service
- Performance degradation — slow queries, high error rates, latency spikes
With SECURENOW_CAPTURE_BODY=1 enabled, SecureNow can also analyze request payloads for injection patterns, giving you deeper visibility into POST and PUT requests hitting your Koa routes.
Recap
| Step | Command / Action | Time |
|---|---|---|
| Install | npm install securenow | 10 s |
| Login | npx securenow login | 20 s |
| Create app | npx securenow apps create my-koa-api | 15 s |
| Configure | Add env vars to .env (body capture ON) | 30 s |
| Instrument | Add require('securenow/register') or use -r flag | 30 s |
| Verify | npx securenow status | 10 s |
Six steps, under five minutes, zero middleware changes. Your Koa API is now observable and protected.
Next Steps
- Explore the SecureNow dashboard to view traces, logs, and security issues
- Set up alert rules for critical security events
- Run
npx securenow forensicsto ask natural-language questions about your traffic - Read the full environment variable reference for advanced tuning
Happy shipping — and happy securing.
Frequently Asked Questions
Does SecureNow capture request bodies with Koa?
Yes. Unlike some frameworks with streaming parsers, Koa paired with koa-bodyparser makes the parsed body available on ctx.request.body before route handlers execute. Set SECURENOW_CAPTURE_BODY=1 to attach request payloads to trace spans. Sensitive fields like passwords and tokens are redacted automatically.
Do I need to add any Koa middleware for SecureNow?
No. SecureNow instruments your application at the Node.js runtime level via the -r preload flag or a require() call. No custom Koa middleware is needed — your existing middleware stack remains untouched.
Will SecureNow work with @koa/router and koa-bodyparser?
Yes. SecureNow's auto-instrumentation recognizes @koa/router (and koa-router) routes, so trace spans include the matched route pattern (e.g., /tasks/:id) rather than raw paths. koa-bodyparser is fully compatible with body capture.
Can I run SecureNow with Koa in PM2 cluster mode?
Yes. Pass -r securenow/register in node_args in your PM2 ecosystem config and set SECURENOW_NO_UUID=1 so all cluster workers report under the same service name in the dashboard.
Recommended reading
A hands-on walkthrough for adding security observability to a Nuxt 3 app using the securenow npm package and official Nuxt module. Covers installation, nuxt.config.ts setup, environment variables, optional tuning, deployment targets, CLI verification, and troubleshooting.
Apr 2Stop juggling --require and --import flags. securenow/register now auto-registers the ESM loader hook via module.register() on Node >=20.6, so a single -r flag is all you need for both CommonJS and ESM apps.
Apr 2Step-by-step guide to integrating SecureNow into a self-hosted Next.js application on AWS EC2. Covers installation, instrumentation, environment configuration, verifying traces and logs, enabling request body capture, and creating alert rules.
Mar 29