Verifying Webhook Signatures (HMAC) in n8n: Complete Guide
Sasha Ray
3rd Sep, 2026

Verifying Webhook Signatures in n8n
Every n8n webhook is a public HTTP endpoint. Anyone who discovers or guesses the URL can send a request to it, and by default n8n will accept that request and run the workflow. Verifying webhook signatures in n8n using HMAC solves this by proving two things at once: that the request came from the provider holding your shared secret, and that the payload was not modified in transit.
Whether you are receiving Stripe payment events, Shopify order updates, GitHub repository activity, or internal service callbacks, signature verification is the difference between an automation you can trust and one that will execute whatever anyone sends it. Teams running payment, order, or customer-data workflows in production commonly Hire n8n Developers to implement verification correctly, because the failure modes are quiet — a workflow that accepts forged requests looks exactly like one that works.
Why Webhook Signature Verification Matters
A webhook URL is a credential in everything but name. It appears in provider dashboards, in browser history, in logs, in support tickets, and in screenshots. Once it leaks, an unverified endpoint will process anything sent to it.
An unverified webhook exposes you to:
Forged events that trigger real business actions such as refunds, shipments, or account changes
Replayed requests that repeat a legitimate event dozens of times
Payload tampering where an amount, status, or record ID is altered in transit
Denial of service through unlimited unauthenticated workflow executions
Data injection into downstream CRM, ERP, or database systems
Execution data bloat from junk requests filling your database
HMAC verification addresses the first three directly. The provider computes a hash of the exact request body using a secret only the two of you know, sends it in a header, and you recompute the same hash and compare. If they match, the payload is authentic and unaltered.
Common Webhook Signature Formats
Every provider does this slightly differently, and the differences matter. Verify each against the provider's own documentation before implementing:
Stripe →
Stripe-Signatureheader, HMAC-SHA256 hex over
timestamp.payload, includes a timestamp for replay protection
GitHub →
X-Hub-Signature-256header, HMAC-SHA256 hex prefixed with
sha256=, computed over the raw body
Shopify →
X-Shopify-Hmac-Sha256header, HMAC-SHA256 encoded as base64, not hex
Slack →
X-Slack-Signatureheader, HMAC-SHA256 hex over
v0:{timestamp}:{body}, with a separate timestamp header
Three variables change between providers: what gets hashed, which encoding is used, and whether a prefix is attached. Getting any one of them wrong produces a mismatch that looks identical to an attack.
The Raw Body Problem
This is where most n8n implementations fail, and it fails silently.
HMAC is computed over the exact bytes the provider sent. By default, the n8n Webhook node parses incoming JSON into a structured object. If you then re-serialise that object to compute a hash, you are hashing a different byte sequence — key order may differ, whitespace is gone, Unicode may be escaped differently. The hash will never match, and no amount of debugging the algorithm will fix it.
The solution is the Webhook node's Raw Body option, available under Add Option. Enabling it makes the node output the unparsed body as binary data rather than parsed JSON, giving you the original bytes to hash. Note that this changes the shape of your node output, so any downstream nodes expecting $json.body will need to parse the raw body themselves after verification passes.
How to Verify Webhook Signatures in n8n
There are two viable approaches. Both are legitimate; the right one depends on the provider.
Approach 1: The Crypto Node
n8n includes a built-in Crypto node with an Hmac action supporting SHA256 and other algorithms, with hex or base64 output, and a Binary File mode that accepts the raw body directly from the Webhook node.
The workflow shape:
Webhook node
— Raw Body enabled, Respond set to "Using Respond to Webhook Node"
Crypto node
— Action: Hmac, Type: SHA256, Binary File: on, Binary Property Name:
data, Encoding: hex or base64 to match your provider
IF node
— compare the computed value against the incoming header
Respond to Webhook node
— 200 on the true branch, 401 on the false branch
Worth knowing: the Crypto node's Hmac action now takes its secret from Crypto credentials (the Hmac Secret field) rather than an inline parameter. That is the correct place for it — the secret is encrypted at rest and never appears in exported workflow JSON.
This approach works cleanly for providers that hash the raw body directly, such as GitHub, Shopify, and Razorpay. It is less suited to Stripe or Slack, where the signed string is a constructed value rather than the body alone.
Approach 2: The Code Node
For providers requiring constructed payloads, timestamp validation, or timing-safe comparison, use a Code node:
jsconst crypto = require('crypto'); const item = $input.first(); const rawBody = Buffer.from(item.binary.data.data, 'base64'); const headers = item.json.headers; // header names arrive lowercased const received = headers['x-hub-signature-256'] || ''; const secret = $env.WEBHOOK_SECRET; const expected = 'sha256=' + crypto .createHmac('sha256', secret) .update(rawBody) .digest('hex'); const a = Buffer.from(expected); const b = Buffer.from(received); // Length check first — timingSafeEqual throws on mismatched lengths. const valid = a.length === b.length && crypto.timingSafeEqual(a, b); return [{ json: { valid, body: JSON.parse(rawBody.toString('utf8')) } }];
Two configuration requirements that catch people out:
The Code node restricts module imports for security. To use require('crypto') you must set NODE_FUNCTION_ALLOW_BUILTIN=crypto. If your instance runs Task Runners, that variable belongs on the Task Runners container rather than the main n8n service.
More importantly, n8n 2.0 changed the default of N8N_BLOCK_ENV_ACCESS_IN_NODE to true, which blocks $env access from Code nodes and expressions. Verification workflows that read their secret from $env will stop working after upgrading. You can set it back to false, but the better answer is the one n8n recommends: store the secret in a credential and use the Crypto node, or supply it through n8n Variables.
Real Business Use Cases
Payment Processing
Stripe and Razorpay events trigger fulfilment, refunds, and ledger entries. An unverified payment webhook allows anyone to fabricate a successful charge. Verification here is not hardening, it is a prerequisite.
E-commerce Order Sync
Shopify order and inventory webhooks feed ERP and warehouse systems. Shopify uses base64 encoding rather than hex, which is the most common single mistake in Shopify implementations.
CRM and Lead Capture
Form and CRM webhooks write directly into customer databases. Without verification, your CRM is an open write endpoint for anyone with the URL.
Internal Service Callbacks
Service-to-service webhooks between your own systems deserve the same treatment. Internal does not mean trusted, particularly in shared cloud networks.
Repository and CI Events
GitHub webhooks that trigger deployments are a direct path to your infrastructure. A forged push event that starts a pipeline is a serious incident.
Why Businesses Choose Professional Implementation
Signature verification looks like a ten-minute task and usually is — until the hash does not match and there is no way to tell whether the cause is body parsing, encoding, a prefix, a constructed payload, or a genuinely forged request.
At this stage, many businesses Hire n8n Developers to implement verification across their webhook estate consistently, add replay protection, and put monitoring in place that distinguishes a misconfiguration from an actual attack.
Handling Failures and Replay Attacks
A valid signature proves authenticity. It does not prove freshness. An attacker who captures a legitimate signed request can send it again, and the signature will still verify.
Two additional controls are needed.
Timestamp validation. Providers that include a timestamp in the signed payload — Stripe and Slack among them — let you reject requests outside a tolerance window, commonly five minutes. Compare the header timestamp against the current time before accepting.
Idempotency. Store the provider's event ID and reject repeats. A short-lived cache or a unique constraint in your database both work. This also protects against the legitimate duplicate deliveries most providers send on retry.
On rejection, respond with 401 and nothing else. Do not return the expected signature, the reason for failure, or any diagnostic detail — that information helps an attacker calibrate. Log the failure internally with the source IP and header values so you can investigate.
Because the Webhook node's default behaviour is to respond before the workflow finishes, set Respond to "Using Respond to Webhook Node" so that you control the status code from the verification branch.
Best Practices for Webhook Security in n8n
Follow these recommendations for reliable, secure webhook handling:
Enable Raw Body on any webhook that will be signature-verified.
Store secrets in credentials, not in Code node literals or workflow JSON.
Match the provider's encoding exactly — hex and base64 are not interchangeable.
Use timing-safe comparison rather than a plain string or IF-node equality check.
Check buffer lengths before calling
timingSafeEqual, which throws on mismatch.
Validate timestamps where the provider supplies them.
Deduplicate on event ID to make workflows idempotent.
Return 401 with no diagnostic detail on failure.
Use the Webhook node's IP Allowlist and Ignore Bots options as defence in depth, not as a replacement for verification.
Rotate webhook secrets on the same schedule as your other credentials.
That last point is the one teams skip. A verification step that has never been tested against a bad signature has not been tested.
Scaling Secure Webhook Handling
As the number of integrations grows, verification logic duplicated across dozens of workflows becomes a maintenance liability. Larger deployments typically consolidate:
A reusable sub-workflow that handles verification for all providers
Per-provider configuration held in credentials rather than in workflow logic
Centralised rejection logging and alerting
Idempotency storage shared across workflows
Automated tests that fire invalid signatures at staging endpoints
Documented secret rotation procedures
With this in place, adding a new signed webhook becomes a configuration change rather than a security review.
Why Choose N8n Developers?
N8n Developers provides experienced engineers who build and secure production n8n environments. From webhook authentication and credential architecture to reusable verification sub-workflows, replay protection, and monitoring that separates misconfiguration from genuine attack traffic, our team delivers automation that holds up under real-world conditions. Whether you need a security review of existing webhooks, implementation across a growing integration estate, or ongoing operational support, we build for long-term reliability.
Future of Webhook Security in Automation
Webhook authentication is moving toward stronger standards. HTTP Message Signatures are being adopted by newer APIs, mutual TLS is becoming common in enterprise integrations, and providers are increasingly shortening replay tolerance windows. n8n's direction of travel supports this: recent releases have tightened Code node defaults and pushed secret handling toward credentials rather than environment variables.
Organisations building automation on webhooks frequently Hire n8n Developers to design authentication architecture that accommodates these changes without rebuilding every workflow.
If your n8n instance is receiving webhooks that are not signature-verified, or you are unsure whether your verification actually works, our team can help. Hire n8n Developers today to audit your webhook endpoints, implement HMAC verification correctly, and add the replay protection and monitoring that production automation requires.
Verifying webhook signatures in n8n comes down to four things: capture the raw body before n8n parses it, compute the HMAC exactly as the provider specifies, compare it in a timing-safe way, and add timestamp and idempotency checks so a valid signature cannot be replayed. The Crypto node handles straightforward cases without code; the Code node covers providers with constructed payloads. Either way, test with a deliberately invalid signature before you trust it — an endpoint that accepts everything and an endpoint that verifies correctly look identical until someone finds the URL.
Frequently Asked Questions
A method where the sender hashes the request body with a shared secret and sends the result in a header, letting you confirm the payload is authentic and unmodified.
Almost always because the Webhook node parsed the JSON before you hashed it. Enable the Raw Body option so you hash the original bytes.
Yes. The Crypto node's Hmac action, combined with an IF node and a Respond to Webhook node, covers providers that sign the raw body directly.
In n8n credentials. From n8n 2.0, environment variable access from Code nodes is blocked by default, so credentials are both safer and more reliable.
No. Signatures prove authenticity, not freshness. Add timestamp validation and deduplicate on the provider's event ID.
Professional developers implement verification consistently across all endpoints, add replay protection, and test the failure path rather than only the happy path.

