npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@prokodo/n8n-nodes-secure-webhook

v0.0.1

Published

Hardened webhook trigger for n8n with HMAC/JWT (JWKS), replay protection, IP policies, mTLS proxy checks, per-IP rate limiting, Redis HA state, and audit export.

Downloads

19

Readme

Production-grade webhook trigger for n8n with HMAC/JWT auth, replay protection, IP policies, mTLS header checks, per-IP rate limiting, Redis HA support, and external audit export — developed by prokodo.

🇺🇸 Need help implementing secure n8n webhooks & workflows (HMAC, JWT/JWKS, mTLS, Redis, rate limits)?
prokodo — n8n Security & Automationclick here

🇩🇪 Sie brauchen Unterstützung bei sicheren n8n Webhooks & Workflows (HMAC, JWT/JWKS, mTLS, Redis, Rate Limits)?
prokodo — n8n Security & Automationhier klicken

npm License: MIT


✨ Features

  • 🔐 Authentication profiles
    • HMAC: raw-body or extended signature (method + path + query + timestamp + nonce + bodyhash)
    • JWT (JWKS): verify Authorization: Bearer <jwt> against your IdP
    • API Key: lightweight static header (best for internal calls)
    • Combo: HMAC + IP allow/deny (CIDR)
  • 🛡️ Replay protection (timestamp + nonce, one-time use)
  • 🧱 Rate limiting per IP (in-memory token bucket or Redis Lua fixed-window)
  • 🌐 IP policies (allow/deny by CIDR) for partner/VPN hardening
  • 📜 mTLS proof via proxy headers (e.g., x-ssl-client-verify: SUCCESS)
  • 🧾 Audit export (best-effort HTTPS POST of accept/reject metadata)
  • 🧰 HA/Cluster-ready with optional Redis for rate+replay state
  • ⚙️ Strict input hygiene: Content-Type allowlist & body size cap
  • 🔁 Dual-key rotation window for HMAC secret rollovers
  • 🧩 UX-friendly node options with comprehensive inline help

Internal node name: prokodoSecureWebhook In the node picker: “Secure Webhook”

🆚 Why not the default n8n Webhook?

| Capability | n8n Default Webhook | Secure Webhook (this node) | |---|---|---| | Auth | Token in URL or basic header patterns | HMAC / JWT (JWKS) / API Key / Combo | | Replay protection | ❌ | Timestamp + Nonce | | Rate limiting | ❌ | Per-IP (memory or Redis) | | IP policies | ❌ | Allow/Deny (CIDR) | | mTLS awareness | ❌ | Proxy header checks | | Audit trail | Minimal | External HTTPS audit events | | HA state | N/A | Redis for nonce & rate data | | Signature scope | N/A | Raw body or Extended (method+path+query+…) |

Bottom line: If your webhook is public-facing or exposed to the internet, this hardened trigger offers defense-in-depth that the default webhook does not.

✅ Requirements

  • Node.js 18+ / 22 LTS
  • n8n ≥ 1.88 (tested on 1.116.2+)
  • (Optional) Redis for HA/cluster setups
  • For HMAC: a shared secret in n8n credentials (hmacSharedSecretApi)
  • For JWT: a reachable JWKS URL (jwtJwksApi) and optional iss/aud
  • For API Key: header name + value (apiKeyHeaderApi)
  • For mTLS headers: a reverse proxy (Nginx/Envoy/Cloudflare) that terminates TLS and forwards verification headers

Using an older n8n (e.g. 1.88)? It may still work if you align n8n-core / n8n-workflow versions. For best results, upgrade n8n.

📦 Install

Option A — Custom extensions folder (recommended)

Local n8n (not Docker):

# choose your custom folder (default ~/.n8n)
export N8N_CUSTOM_EXTENSIONS=~/.n8n

# install your built package into that folder
npm install --prefix "$N8N_CUSTOM_EXTENSIONS" @prokodo/n8n-nodes-secure-webhook

# start n8n
n8n start

Docker (example Dockerfile):

FROM n8nio/n8n:latest

ENV N8N_CUSTOM_EXTENSIONS=/home/node/.n8n
ENV NODE_PATH=/home/node/.n8n/node_modules

USER node
RUN npm install --prefix /home/node/.n8n @prokodo/n8n-nodes-secure-webhook@latest

After starting n8n, search in the node picker for “Secure Webhook” Internal name: prokodoSecureWebhook

🛠 Dev install (build + link locally)

# in this repo
npm ci
npm run build

# make your package linkable
npm link

# link into your n8n custom extensions folder
npm link @prokodo/n8n-nodes-secure-webhook --prefix ~/.n8n

# start n8n with your custom folder
export N8N_CUSTOM_EXTENSIONS=~/.n8n
n8n start

Publish-ready tip: This package publishes compiled JS from dist/ to npm. You don’t need to commit dist/ to Git. To support installs straight from GitHub, add:

"scripts": {
  "prepare": "npm run build"
}

…and commit src/ (not dist/).

🔧 Webhook Endpoint

Path: /secure, method: POST, response mode: onReceived.
Final URL (default n8n): https://<your-host>/webhook/secure

🔐 Credentials

  • HMAC → Create credentials hmacSharedSecretApi and set your shared secret.
  • JWT (JWKS) → Create jwtJwksApi with your JWKS URL (e.g., Auth0/Okta). Optionally set jwtIss/jwtAud in the node.
  • API Key → Create apiKeyHeaderApi with headerName (e.g., x-api-key) and value.

Pick the Security Profile in the node to match the credential type you configured.

🧩 Node Options (Field Guide)

Core

Security Profile

  • HMAC — safest default for public internet
  • jwks (JWT) — for IdPs like Auth0/Okta/OIDC
  • apikey (Static header) — simple, for internal clients
  • combo — HMAC + IP allow/deny

Shared safety

  • Trusted Proxy Hops — how many X-Forwarded-For hops you trust (e.g., Cloudflare + Nginx = 2)
  • Max Body (bytes) — reject large payloads early (default 1 MB)
  • Allowed Content-Types — comma-separated allowlist (default: application/json,application/x-www-form-urlencoded)
  • Rate Limit / Minute (per IP) — default 120. With Redis it’s cluster-wide; otherwise per process

Replay Protection

  • Timestamp Header (x-timestamp) — UNIX seconds, 10 digits
  • Nonce Header (x-nonce) — unique per request (UUID v4 or 16–32B hex)
  • Max Skew (sec) — default 300; tune based on client/server time sync

HMAC (recommended/combo)

  • HMAC Signature Header (x-signature) → value like sha256=<hex>
  • HMAC Algorithmsha256 (default) or sha512

Signature Mode

  • body — sign raw body with HMAC (compatibility)
  • extended — method + path + canonical query + timestamp + nonce + bodyhash (strongest)

Dual-Key Rotation

  • Previous Secret — optional, for rolling changes
  • Dual-Key Window (min) — accept previous secret briefly during rotation

IP Policies (combo)

  • IP Allow (CIDR) — only allow these ranges
  • IP Deny (CIDR) — block these ranges first (deny takes precedence)

JWT (JWKS)

  • JWT Issuer (iss) — optional but recommended
  • JWT Audience (aud) — optional but recommended
  • JWKS Cooldown (ms) — min interval between JWKS fetches (default 60s)
  • JWKS Fetch Timeout (ms) — network timeout (default 3s)

mTLS via Proxy

  • Require mTLS Header — expect proof from your proxy (e.g., x-ssl-client-verify: SUCCESS)
  • Verify Header — default x-ssl-client-verify
  • Subject Header — default x-ssl-client-dn
  • Subject Allow Regex — optional (^CN=partner\.), fail-closed on bad regex

Audit Export

  • Audit Exportnone or https
  • Audit Endpoint URL — HTTPS receiver of compact JSON events
  • Audit Bearer Token — optional Authorization: Bearer <token>

🔐 Client Integration Scenarios

1) HMAC (Recommended)

Server:

  • Create credentials hmacSharedSecretApi with your shared secret.
  • Profile: Empfohlen (HMAC).
  • Keep default timestamp/nonce headers unless you need custom names.

Client (Node.js, extended mode):

  import crypto from 'node:crypto';

  const url = 'https://your-n8n.example/secure?foo=bar';
  const body = JSON.stringify({ hello: 'world' });
  const ts = Math.floor(Date.now()/1000).toString();
  const nonce = crypto.randomUUID();
  const algo = 'sha256';

  // body hash
  const bodyHash = crypto.createHash(algo).update(Buffer.from(body)).digest('hex');

  // canonicalize query
  const { URL } = await import('node:url');
  const u = new URL(url);
  const query = [...u.searchParams.entries()]
    .sort(([a],[b]) => a.localeCompare(b))
    .map(([k,v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
    .join('&');

  // base string
  const base = ['POST', u.pathname, query, ts, nonce, bodyHash].join('\n');

  // hmac
  const signatureHex = crypto.createHmac(algo, process.env.WEBHOOK_SECRET).update(base).digest('hex');

  const resp = await fetch(url, {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
      'x-timestamp': ts,
      'x-nonce': nonce,
      'x-signature': `${algo}=${signatureHex}`,
    },
    body,
  });
  console.log(resp.status, await resp.text());

curl (body mode):

TS=$(date +%s)
NONCE=$(uuidgen)
BODY='{"hello":"world"}'
SIG_HEX=$(printf %s "$BODY" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" -binary | xxd -p -c 256)

curl -X POST "https://your-n8n.example/secure" \
  -H "content-type: application/json" \
  -H "x-timestamp: $TS" \
  -H "x-nonce: $NONCE" \
  -H "x-signature: sha256=$SIG_HEX" \
  --data "$BODY"

2) JWT (JWKS)

Server:

  • Create credentials jwtJwksApi with your JWKS URL.
  • Profile: JWT (JWKS). Optionally set jwtIss/jwtAud.

Client:

curl -X POST "https://your-n8n.example/secure" \
  -H "content-type: application/json" \
  -H "authorization: Bearer $JWT" \
  --data '{"ok":true}'

3) API Key (Internal)

Server:

  • Create credentials apiKeyHeaderApi with:
    • headerName: e.g., x-api-key
    • value: your static secret
  • Profile: Einfacher API Key.

Client:

curl -X POST "https://your-n8n.example/secure" \
  -H "content-type: application/json" \
  -H "x-api-key: YOUR_SECRET" \
  --data '{"ok":true}'

4) Combo (HMAC + IP Allow/Deny)

Server:

  • Profile: Kombiniert.
  • Configure HMAC and IP Allow/Deny CIDRs.

Client: Same as HMAC, but requests must originate from allowed networks.


🔁 HMAC Secret Rotation (Playbook)

  1. Set Previous Secret = current secret; deploy the node with a Dual-Key Window (e.g., 60 min).
  2. Distribute the new secret to clients and switch their signing key.
  3. After the window elapses and traffic is fully migrated, clear Previous Secret.

🧭 Reverse Proxy (mTLS Header) Example

Nginx:

ssl_verify_client on;          # request client cert
ssl_client_certificate /etc/nginx/ca_chain.pem;

location /secure {
  proxy_pass http://n8n:5678/secure;
  proxy_set_header x-ssl-client-verify $ssl_client_verify; # "SUCCESS" on pass
  proxy_set_header x-ssl-client-dn     $ssl_client_s_dn;
}

Node settings

  • Enable Require mTLS Header
  • Keep defaults or adjust header names
  • Optionally Subject Allow Regex like ^CN=partner\.

🧮 Rate Limiting Details

  • In-memory (default): token bucket (burst friendly), per process
  • Redis (optional): fixed window via atomic Lua (EVALSHA), cluster-safe

Fields

  • Rate Limit / Minute (per IP): max hits per 60s
  • Redis aktivieren / URL / Namespace: shared state across nodes
  • Returns 429 with Retry-After when exceeded

🗂 Audit Export (Best-Effort)

If enabled, the node POSTs a compact JSON event to your endpoint:

{
  "ts": "2025-01-01T10:00:00.000Z",
  "rid": "9f2a…",
  "ip": "203.0.113.42",
  "profile": "recommended",
  "outcome": "accept",
  "reason": "bad_signature"
}
  • No request payload is sent (metadata only).
  • Failures are swallowed to avoid breaking the main request path.

🔒 Security Model (At a Glance)

  • Input hygiene: strict Content-Type allowlist, body size cap
  • Auth: HMAC/JWT/API Key; extended HMAC defends against path/query tampering
  • Replay: timestamp + nonce (short TTL); requires client time sync
  • Abuse: per-IP rate limiting; optional IP allow/deny (CIDR)
  • Transport: terminate TLS at edge; optional mTLS forwarding
  • State: Redis for HA (nonces & rate); memory fallback for simple installs
  • Audit: external events for SIEM/forensics (no payload leakage)

🧪 Testing Checklist

  • ✅ Valid Content-Type and within Max Body
  • ✅ Include x-timestamp (10-digit seconds) within Max Skew
  • ✅ Include x-nonce (unique per request)
  • HMAC: correct signature (body/extended mode)
  • JWT: valid token & reachable JWKS; iss/aud match if configured
  • Rate limiting: send > rateMax/min to observe 429 + Retry-After
  • IP policy behavior (allow/deny)
  • ✅ (Optional) mTLS headers forwarding via proxy
  • ✅ Observe x-request-id and audit events

🧯 Troubleshooting

  • 415 unsupported_content_type → Add client’s type to Allowed Content-Types
  • 413 payload_too_large → Increase Max Body or shrink payload
  • 401 bad_or_missing_timestamp → Ensure x-timestamp within Max Skew
  • 401 replay_detected → Use a fresh x-nonce for every request
  • 401 bad_signature / bad_signature_algo → Check algorithm/header and base string mode
  • 401 invalid_token / missing_bearer → Send Authorization: Bearer <jwt>; verify IdP/JWKS
  • 401 mtls_* → Confirm proxy sets verification headers
  • 403 ip_denied / ip_not_allowed → Adjust IP Deny/Allow CIDRs
  • 429 rate_limited → Decrease traffic, raise threshold, or enable Redis

🧠 Best Practices

  • Prefer HMAC extended mode for public endpoints.
  • Keep Max Skew low (120–300s) and ensure NTP on all systems.
  • Rotate HMAC secrets regularly; use Dual-Key Window during rollouts.
  • For HA/Cluster, enable Redis (protect with TLS/network policy).
  • Terminate TLS at the edge; add mTLS for partner integrations.
  • Use precise CIDRs in IP allow lists (avoid wildcards).
  • Log/trace with x-request-id end-to-end.

🙌 Contributing

PRs welcome!

npm ci
npm run build

Open a PR with what changed and how to test it.

📄 License

This library is published under MIT.

© 2025 prokodo. Visit us at prokodo.com.