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.

Lhoussine
Mar 26, 2026·9 min read
getting started securenow feathers

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
VariablePurpose
SECURENOW_APPIDIdentifies your app in the dashboard. Use the key from Step 3.
SECURENOW_INSTANCEOTLP collector URL. Free trial default shown above.
SECURENOW_LOGGING_ENABLEDSet to 1 to forward console.log/warn/error as OTel logs.
SECURENOW_CAPTURE_BODYSet 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

CommandWhat It Does
securenow tracesList recent traces
securenow traces show <traceId>Inspect a single trace
securenow traces analyze <traceId>AI-powered trace analysis
securenow logsList recent logs
securenow issuesView detected security issues
securenow analyticsTraffic and performance analytics
securenow ip <address>Look up an IP address
securenow blocklist add <ip>Block a malicious IP
securenow alerts rulesManage alert rules
securenow forensicsRun 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

StepCommand / ActionTime
Installnpm install securenow10 s
Loginnpx securenow login20 s
Create appnpx securenow apps create my-feathers-api15 s
ConfigureAdd env vars to .env30 s
InstrumentAdd require('securenow/register') as first line30 s
Verifynpx securenow status10 s

One package, one line, full coverage. Your Feathers API — Express transport and all services — is now observable and protected.

...

Next Steps

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

Getting Started with SecureNow and Nuxt 3 — Add Security Monitoring in Under 2 Minutes

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 2
One Flag to Trace Them All — `-r securenow/register` Now Works for ESM and CJS

Stop 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 2
Add Security Monitoring to a Next.js App with SecureNow — Traces, Logs, and Body Capture on AWS

Step-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
deploy nextjs hacker news aws securenow