n8n webhook auth is Basic, Header or JWT: verify Sume's HMAC yourself
n8n's Webhook node offers Basic, Header and JWT auth, none of which checks Sume's HMAC. Verify sume-v1 over timestamp.raw_body in code, 300 second window.

n8n's built-in Webhook authentication cannot validate a Sume signature, because Sume signs the raw body with HMAC SHA-256 and sends the result in a header. So leave n8n auth for what it does well, and add a verification step that recomputes the HMAC and rejects bad or stale deliveries.
Below are the two schemes side by side and a verifier you can place in a Code node or a small service.
n8n authentication options
| Option | What it checks |
|---|---|
| Basic auth | A username and password credential you define |
| Header auth | A header name and value you define |
| JWT auth | A JSON Web Token credential |
| None | Nothing |
| Raw Body option | Lets the node receive the body as raw data, which an HMAC check needs |
What Sume sends
| Item | Value |
|---|---|
| Signed string | <timestamp>.<raw_body>, HMAC SHA-256 |
| Headers | x-sume-webhook-timestamp, x-sume-webhook-signature (sume-v1=<hex>), x-sume-webhook-secret-fingerprint |
| Rotation | The signature header carries one sume-v1= entry per live secret, comma separated |
| Replay window | Reject timestamps outside a tolerance; five minutes (300 s) is the documented default |
| Secret | Dashboard Webhooks tab, or GET /v1/webhooks/signing-secret with account:read |
A verifier
This is plain Node. Check that your n8n deployment allows the crypto module in code steps before you rely on it, or run it in a tiny service in front of n8n. Feed it the raw body, not re-serialised JSON, because any change to the bytes breaks the signature. The Sume TypeScript SDK also exports a verifyWebhook helper.
import crypto from "node:crypto";
export function verifySume({ rawBody, timestamp, header, secret, tolerance = 300 }) {
if (!secret) throw new Error("refusing to verify with an empty secret");
const ts = Number(timestamp);
if (!Number.isFinite(ts)) return false;
if (Math.abs(Date.now() / 1000 - ts) > tolerance) return false;
const digest = crypto
.createHmac("sha256", secret)
.update(`${ts}.${rawBody}`)
.digest("hex");
const want = Buffer.from(`sume-v1=${digest}`);
const results = header.split(",").map((entry) => {
const got = Buffer.from(entry.trim());
return got.length === want.length && crypto.timingSafeEqual(got, want);
});
return results.includes(true);
}Layering it with n8n auth
- Keep Header auth on the Webhook node as a cheap first gate if you like, but never treat it as proof the body came from Sume.
- Store the Sume signing secret in n8n credentials or an environment variable, never in the workflow JSON.
- After verification, dedupe on job_id and return 2xx fast. Sume gives each attempt 10 seconds and tries up to 10 times.
- When verification fails after rotation, compare x-sume-webhook-secret-fingerprint with the fingerprint in the dashboard rather than sending the secret anywhere.
Sources
Related posts
More in Integrations
- Notion API image block with a Sume URL: PNG works, WebP is not listed
Notion's external image block needs a directly hosted, public URL, and its file-type list has no WebP. Ask Sume for png or jpeg, then append the block.
- Notion audio block from a Sume music URL: the extension check
Notion's external audio block lists .mp3, .wav, .ogg, .oga and .m4a. Check that the Sume artifact URL path ends in one; if not, use Notion's File Upload.
- Obsidian plugin: call Sume with requestUrl and embed the image
Obsidian's requestUrl skips CORS limits, so a plugin can POST to Sume's /v1/images. Save the file with createBinary and insert an embed. Handle the 202 case.
- Odysee 16 GB upload limit vs a 1800-second Sume source
Odysee caps uploads at 16 GB. A 1800-second Sume source would need about 71 Mbps to reach it. Worked sizes at 8, 25 and 50 Mbps, with a Python check.
Written by Sume