How to Secure Your Feathers App with SecureNow — Full-Stack Service Monitoring
End-to-end guide for adding security monitoring to a Feathers.js application with SecureNow. Covers Express transport, service layer tracing, and production deployment.

How to Secure Your Feathers App with SecureNow — Full-Stack Service Monitoring
Feathers.js gives you a service-oriented architecture with real-time events, hooks, and a clean separation between transport and business logic. Under the hood, most Feathers apps use Express as their HTTP transport — which means SecureNow auto-instruments both the Express layer and every Feathers service endpoint in a single step.
This guide walks through the complete setup: installing the package, authenticating with the CLI, creating an app on the free trial, wiring up environment variables, instrumenting a Feathers server with a custom service, and verifying that traces land in the dashboard.
Prerequisites
- Node.js 18+ installed
- An existing Feathers project (or willingness to scaffold one below)
- A terminal and a browser
No SecureNow account yet? The CLI will open a browser-based signup/login flow for you.
Step 1: Install the Package
npm install securenow
Your project should already have Feathers dependencies installed (@feathersjs/feathers, @feathersjs/express, etc.). SecureNow does not need a Feathers-specific plugin — it instruments Express (Feathers' HTTP transport) and the Node.js http module automatically.
Step 2: Log In via the CLI
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.
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)
npx securenow apps create my-feathers-api
Choose Free Trial when prompted. Output:
✔ Application created
SECURENOW_APPID=a1b2c3d4-e5f6-7890-abcd-ef1234567890
SECURENOW_INSTANCE=https://freetrial.securenow.ai:4318
Add these to your .env file.
Optionally set it as your default:
npx securenow config set defaultApp a1b2c3d4-e5f6-7890-abcd-ef1234567890
Step 4: Configure Environment Variables
Create (or update) a .env file in your project root:
SECURENOW_APPID=a1b2c3d4-e5f6-7890-abcd-ef1234567890
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. Works with Feathers' Express transport — sensitive fields are automatically redacted. |
Step 5: Instrument Your Feathers App
Add require('securenow/register') as the very first line of your entry file — before any Feathers or Express imports. Since Feathers uses Express as its HTTP transport, SecureNow auto-instruments both layers.
require('securenow/register');
require('securenow/console-instrumentation');
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const { NotFound } = require('@feathersjs/errors');
class TaskService {
constructor() {
this.tasks = [];
this.nextId = 1;
}
async find(params) {
console.log('Finding tasks', { query: params.query });
return this.tasks;
}
async get(id) {
const task = this.tasks.find((t) => t.id === Number(id));
if (!task) throw new NotFound(`Task ${id} not found`);
return task;
}
async create(data) {
const task = { id: this.nextId++, ...data, completed: false };
console.info('Creating task', { title: task.title });
this.tasks.push(task);
return task;
}
async patch(id, data) {
const task = this.tasks.find((t) => t.id === Number(id));
if (!task) throw new NotFound(`Task ${id} not found`);
Object.assign(task, data);
return task;
}
async remove(id) {
const index = this.tasks.findIndex((t) => t.id === Number(id));
if (index === -1) throw new NotFound(`Task ${id} not found`);
return this.tasks.splice(index, 1)[0];
}
}
const app = express(feathers());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.configure(express.rest());
app.get('/api/health', (req, res) => {
res.json({ status: 'ok' });
});
app.use('/api/tasks', new TaskService());
app.use(express.notFound());
app.use(express.errorHandler());
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
SecureNow instruments Express middleware dispatch, HTTP request/response lifecycle, and any outbound calls your services make. Feathers service methods (find, get, create, patch, remove) execute inside the request trace span, so their timing and errors are captured automatically.
Alternative: Zero Code Changes with NODE_OPTIONS
If you prefer not to modify your entry file:
NODE_OPTIONS="-r securenow/register -r securenow/console-instrumentation" node app.js
Or add it to package.json:
{
"scripts": {
"start": "node app.js",
"start:observe": "NODE_OPTIONS='-r securenow/register -r securenow/console-instrumentation' node app.js"
}
}
Step 6: Start and Verify
Run your app:
node app.js
You should see:
[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
Server running on port 3000
Generate some traffic against the Feathers service:
curl http://localhost:3000/api/health
curl http://localhost:3000/api/tasks
curl -X POST http://localhost:3000/api/tasks -H "Content-Type: application/json" -d '{"title":"Write docs","priority":"high"}'
curl http://localhost:3000/api/tasks/1
curl -X PATCH http://localhost:3000/api/tasks/1 -H "Content-Type: application/json" -d '{"completed":true}'
Check your dashboard:
npx securenow status
You should see your app listed as protected. Browse traces:
npx securenow traces
Or open the full dashboard at app.securenow.ai. You will see traces for each Feathers service call — find, get, create, patch — all nested under the parent HTTP request span.
Bonus: Useful CLI Commands
| 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-feathers-api',
script: './app.js',
instances: 4,
exec_mode: 'cluster',
node_args: '-r securenow/register -r securenow/console-instrumentation',
env: {
SECURENOW_APPID: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
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-feathers-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"]
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
Because Feathers services are exposed over HTTP via Express, every request flows through the same instrumentation pipeline. Whether a client calls POST /api/tasks or uses a Feathers client over REST, the trace is captured and analyzed.
Recap
| Step | Command / Action | Time |
|---|---|---|
| Install | npm install securenow | 10 s |
| Login | npx securenow login | 20 s |
| Create app | npx securenow apps create my-feathers-api | 15 s |
| Configure | Add env vars to .env | 30 s |
| Instrument | Add require('securenow/register') as first line | 30 s |
| Verify | npx securenow status | 10 s |
One package, one line, full coverage. Your Feathers API — Express transport and all services — 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 trace Feathers service hooks and lifecycle events?
SecureNow auto-instruments the Express HTTP transport that Feathers uses under the hood. Every incoming HTTP request — whether it hits a REST endpoint, a custom route, or a Feathers service — is captured as a trace span. Feathers hooks execute within that request span, so their timing is included in the trace waterfall.
Does SecureNow work with Feathers v5 (Dove) and the Koa transport?
SecureNow instruments both Express and Koa at the Node.js level. If your Feathers v5 app uses @feathersjs/koa as its HTTP transport, traces are captured automatically. The setup is identical — just require('securenow/register') as the first line.
Can I capture request bodies with Feathers?
Yes. Set SECURENOW_CAPTURE_BODY=1 in your environment. Since Feathers uses Express (or Koa) for HTTP parsing, the body is available on the Node.js request stream and SecureNow captures it. Sensitive fields like passwords and tokens are automatically redacted.
Will SecureNow detect attacks against Feathers custom services?
Yes. SecureNow analyzes the full HTTP request — URL, headers, query parameters, and optionally the body — regardless of which Feathers service handles it. SQL injection in query params, path traversal, and anomalous traffic patterns are all detected at the HTTP layer.
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