Affiliate/Ads disclaimer: Some links on this blog are affiliate/ads links to support this project going on, meaning I may earn a commission at no extra cost to you.
n8n Webhook Security: HMAC, Auth Headers & IP Allowlisting
Securing n8n webhooks requires layered authentication because the default Webhook node, while supporting Basic Auth, Header Auth, and JWT credential modes, does not natively verify payload integrity or prevent replay attacks. HMAC‑SHA256 signatures cryptographically bind each request to a shared secret, proving authenticity and detecting tampering. Complementary layers—IP allowlisting, raw body capture, and timing‑safe comparison—combine to close gaps that any single method leaves open. [1]
| Method | Security Level | Verifies Sender | Detects Tampering | Prevents Replay | Best For |
|---|---|---|---|---|---|
| HMAC‑SHA256 | High | ✅ | ✅ | ⚠️ (with timestamp) | Stripe, GitHub, Slack |
| Header Auth | Medium | ✅ | ❌ | ❌ | Internal APIs, trusted senders |
| Basic Auth | Medium | ✅ | ❌ | ❌ | Simple password‑protected endpoints |
| IP Allowlisting | Low (alone) | ⚠️ | ❌ | ❌ | Layered with HMAC or API keys |
How do you implement HMAC‑SHA256 signature verification for n8n webhooks?
Enable “Raw Body” on the Webhook node, then place a Code node immediately
after it. Use crypto.createHmac('sha256', secret).update(rawBody)
to recompute the signature, and compare it to the header value. If
they mismatch, throw an error to halt execution. Store the secret in an
environment variable, never hardcoded in the workflow.
[2]
For production, always use crypto.timingSafeEqual() instead of
string equality to prevent timing attacks. An IF node downstream can route
valid requests to business logic and invalid ones to a 403 response. For
integration‑specific implementations, see pre‑built templates for Stripe,
GitHub, and Slack verification in our
credential security guide.
When should you use Header Auth instead of Basic Auth for n8n webhooks?
Use Header Auth when you need a custom header like
X‑API‑Key: your‑key or
Authorization: Bearer <token>—it integrates cleanly
with middleware expecting non‑standard authentication schemes. Basic Auth
sends a base64‑encoded username:password pair in the standard
Authorization header, suitable for simple password‑protected endpoints.
[3]
Both methods verify who is calling, but neither verifies payload integrity— a signed Header Auth token can still carry a tampered body. Combine them with HMAC for defense‑in‑depth. For examples of API‑key gating patterns, see the DevOps webhook alerting guide.
How do you configure IP allowlisting for n8n webhook nodes?
In the Webhook node’s “Options” panel, add comma‑separated CIDR ranges
like 34.195.0.0/16, 54.208.0.0/15 to the “IP(s) Allowlist”
field. n8n rejects any request whose source IP does not match an entry.
For platforms like Stripe that publish fixed IP ranges, this adds a
strong network‑layer filter before authentication logic runs.
[3]
For more on credential and key management alongside network controls, refer to the n8n Security Hub.
How do you protect n8n webhook URLs from unauthorized discovery and forgery?
Each webhook URL contains a high‑entropy UUID that is unguessable, but authenticated n8n users with workflow access can view it. Never expose the URL in public documentation, git repositories, or client‑side JavaScript. Rotate the webhook URL by deleting and recreating the node if the URL is ever leaked externally. [3]
For n8n Cloud and self‑hosted deployments behind a reverse proxy, set
N8N_PROXY_HOPS to ensure the correct client IP reaches the
allowlist logic. On the network level, restrict the listening interface
via N8N_HOST=127.0.0.1 and terminate TLS at the reverse
proxy. For complete network hardening, see the
n8n architecture guide.
How do you validate webhook payload integrity with HMAC‑SHA256 signatures?
Compute the expected HMAC‑SHA256 signature from the raw request body
using a pre‑shared secret, then compare it to the signature header the
sender provides (e.g., x‑signature or
x‑hub‑signature‑256). Use crypto.timingSafeEqual()
in a Code node for timing‑safe comparison. Reject the request immediately
if signatures differ.
[1]
Common pitfalls include hashing parsed JSON instead of the raw body (even minor formatting differences invalidate the signature) and using non‑constant‑time string comparison. Verify the timestamp to prevent replay attacks: accept only requests with a timestamp within a 5‑minute window. For external secret rotation without touching workflows, see the vault integration guide.
How do you combine HMAC, auth headers, and IP allowlisting into one webhook?
Layer IP allowlisting first at the network level to reject unknown sources immediately. Then validate the HMAC‑SHA256 signature to confirm the payload hasn’t been tampered with. Finally, use Header Auth (API key or JWT) to identify the specific tenant or sender. This layered pattern creates defense‑in‑depth—each layer blocks a different attack vector. [5]
For high‑security environments, add replay protection with a nonce‑plus‑timestamp scheme stored in Redis. The community Secure Webhook node bundles all these layers into a single trigger, but you can also implement them manually with n8n’s stock nodes for full control. For monitoring and alerting on blocked requests, integrate with the DevOps incident response workflows.
References
- Secure AI Agent Webhook with HMAC, Replay Protection, and OpenAI GPT-5 — n8n Template
- HMAC Verification for Secure Webhooks in n8n — Toolient
- n8n Webhook Node Documentation
- CVE‑2025‑68949: n8n Webhook Node IP Whitelist Bypass — Dependabot Advisory
- @prokodo/n8n-nodes-secure-webhook — Community Node with Multi‑Layer Security
- API Authentication and Security for Business Automation: Protect Your n8n Integrations — Serenichron

