Skip to main content

Production & Security

The Bridge Endpoint is a public HTTP route, so Novu Framework includes builtin protections to ensure only Novu Cloud can invoke it.

HMAC Authentication

Each request from Novu Cloud to your Bridge includes a Novu-Signature header containing a timestamp and a signature. The Framework’s serve wrapper verifies the signature against NOVU_SECRET_KEY before invoking your workflow handler.

Header format

Novu-Signature: t=<timestamp>,v1=<signature>
  • t=<unix_seconds> — when the request was signed
  • v1=<sha256_signature> — current valid signature scheme (more may come; always begin with v)

When is HMAC enforced?

NODE_ENVHMAC verification
developmentDisabled — required for the Studio to reach your local bridge
anything else (incl. production, staging, undefined)Enabled
You don’t write any verification code — serve() handles it.

Override behavior

import { Client as NovuFrameworkClient } from "@novu/framework";
import { serve } from "@novu/framework/next";

export const { GET, POST, OPTIONS } = serve({
  client: new NovuFrameworkClient({
    secretKey: process.env.NOVU_SECRET_KEY,
    strictAuthentication: false, // Disables HMAC — DEV ONLY
  }),
  workflows: [/* … */],
});
Never disable strictAuthentication in production. Without HMAC, anyone who can reach your bridge URL can trigger arbitrary step resolution and exfiltrate subscriber/payload data.

Network Requirements

  • Public HTTPS — your bridge must be reachable from the public internet.
  • No IP allowlist published — Novu Cloud workers autoscale; we don’t expose stable IPs.
  • No auth middleware on /api/novu — Novu authenticates with HMAC, not with your app’s JWT/session.
If you need to harden the perimeter:
  • Place a WAF in front, but allow traffic to /api/novu (or whatever path you mounted).
  • Use rate limiting per HMAC header (each request includes a recent timestamp).
  • Log and alert on signature failures — they may indicate a misconfigured bridge URL or a hostile actor.

Compliance

Novu Cloud workers are:
  • GDPR compliant
  • SOC 2 Type II certified
  • ISO 27001 certified
Bridge requests carry only the data necessary to resolve a step: subscriber id (and any subscriber attributes you reference), payload (which you defined the schema for), and step controls. No additional telemetry is exfiltrated.

Environment Variables

The Framework reads these env vars by default (you can override with the Client class):
VariableDefaultPurpose
NOVU_SECRET_KEYHMAC signing key; verifies request authenticity
NOVU_API_URLhttps://api.novu.coCloud API URL — set to https://eu.api.novu.co for EU
NODE_ENVIf development, HMAC is disabled

EU Region Setup

import { Client as NovuFrameworkClient } from "@novu/framework";
import { serve } from "@novu/framework/next";

export const { GET, POST, OPTIONS } = serve({
  client: new NovuFrameworkClient({
    secretKey: process.env.NOVU_SECRET_KEY,
  }),
  workflows: [/* … */],
});
NOVU_API_URL=https://eu.api.novu.co
NOVU_SECRET_KEY=<eu_secret_key>

Best Practices

  1. Keep NOVU_SECRET_KEY server-only — never commit it, never expose to the client. Use your platform’s secrets manager (Vercel Env Vars, AWS Secrets Manager, GitHub Encrypted Secrets).
  2. Rotate the secret key periodically — go to dashboard.novu.co/api-keys, create a new key, deploy it, then revoke the old one.
  3. Use separate keys per environment — Dev and Prod must have different NOVU_SECRET_KEY values.
  4. Audit logs — log every Bridge request server-side with subscriber id and workflow id so you can trace any anomaly.
  5. Set request timeout — keep your step.custom operations under 30s. Longer operations should be enqueued (BullMQ, SQS) and resolved in a separate workflow.
  6. Don’t return secrets in step output — anything in subject/body/data is delivered to the user.
  7. Use HMAC for the Inbox too — see inbox-integration HMAC section.

HMAC for the Inbox vs HMAC for the Bridge

These are separate but related:
Bridge HMACInbox HMAC
DirectionCloud → BridgeInbox SDK → Cloud
PurposeAuthenticate Novu’s call to your serverAuthenticate the subscriber’s session
Header / ParamNovu-Signature (auto by serve)subscriberHash prop on <Inbox>
Computed howCloud signs with NOVU_SECRET_KEYYou compute HMAC-SHA256(secretKey, subscriberId) server-side
Both use the same NOVU_SECRET_KEY. See inbox-integration references for the Inbox HMAC details.

Vercel Preview URLs

Vercel free-tier preview deployments are protected by default. Two ways to make the bridge reachable:

1. Bypass token (for sync only)

Enable Protection Bypass for Automation:
npx novu@latest sync \
  --bridge-url "https://my-app-preview.vercel.app/api/novu?x-vercel-protection-bypass=$BYPASS" \
  --secret-key $NOVU_SECRET_KEY

2. Disable protection on the preview branch (for runtime triggers)

Vercel Pro/Enterprise lets you disable Deployment Protection on a per-branch basis. Useful if you trigger workflows during preview integration tests.