n8n webhook signature verification failing – Stripe rawBody fix

Step by Step Guide to solve n8n Webhook Missing signature Error

 

 


 

Who this is for: n8n developers who need to receive signed webhooks from external services (GitHub, Stripe, Slack, custom APIs) and want a reliable, production‑ready way to validate them. We cover this in detail in the n8n Node Specific Errors Guide.


Quick Diagnosis

  1. Enable the “Signature” option on the Webhook node and store the secret in an environment variable.
  2. Send the x-n8n-signature header – its value must be the HMAC‑SHA256 of the raw request body using the same secret.
  3. Confirm no proxy or CDN strips the header – view the raw request in the execution log.
  4. If the provider uses a different header name, copy it to x-n8n‑signature with a Set node before validation.

Following this three‑step checklist resolves > 95 % of “missing signature” cases.


1. What “Signature” Means for an n8n Webhook

If you encounter any n8n http request node error 401 resolve them before continuing with the setup.

Purpose: Verify that the payload really originates from the trusted sender and has not been tampered with.

Concept n8n Implementation Typical Use‑Case
Signature header x-n8n-signature (HMAC‑SHA256) GitHub, Stripe, Slack, custom services
Secret User‑defined string (recommended via ENV variable) Shared secret between sender and n8n
Verification flow n8n recomputes HMAC_SHA256(secret, raw_body) → compares to header Prevent tampering & replay attacks

EEFA tip – Never hard‑code the secret. Use {{$env.SECRET_WEBHOOK}} to keep it out of logs and version control.


2. Why the “Missing signature” Error Appears

If you encounter any n8n http request node timeout resolve them before continuing with the setup.

# Root Cause Detection Method
1 Header not sent (x-n8n-signature missing) Check Full Request tab in the execution log
2 Provider uses a different header name (e.g., X-Hub-Signature-256) Compare service docs with n8n’s expected header
3 Empty or non‑JSON body → HMAC of empty string Inspect Request Body in the log
4 Secret mismatch (different string, extra spaces) Verify exact secret value on both sides
5 Proxy / load balancer strips custom headers Echo all incoming headers with a temporary Set node
6 Encoding mismatch (UTF‑8 vs. UTF‑16) Re‑compute HMAC locally using the same encoding

3. Step‑by‑Step Fix Guide

3.1 Verify Webhook Node Configuration

  1. Open the Webhook node → Security → enable Signature.
  2. Set Secret to an environment variable: {{$env.SECRET_WEBHOOK}}.
  3. (Optional) Change Header Name if your provider uses a custom name – see 3.4.

3.2 Test with curl – Compute the Signature

Define the secret and payload

# Secret shared with the external service
SECRET="mySuperSecret123"

# Example JSON payload
BODY='{"event":"order.created","id":42}'

Generate the HMAC‑SHA256 signature

SIGNATURE=$(echo -n "$BODY" |
  openssl dgst -sha256 -hmac "$SECRET" -binary |
  xxd -p)

Send the request

curl -X POST "https://your-n8n-instance.com/webhook/abc123" \
  -H "Content-Type: application/json" \
  -H "x-n8n-signature: $SIGNATURE" \
  -d "$BODY"

If the request succeeds, the issue is on the client side (missing/incorrect header, wrong secret, etc.).

3.3 Capture a Different Header Name

When the external service sends X-Hub-Signature-256 (GitHub) instead of x-n8n-signature, add a **Set** node *before* the Webhook node validates the request:

Field Value (Expression)
x-n8n-signature {{$json["X-Hub-Signature-256"]}}

EEFA tip – Place the Set node immediately after the Webhook node’s “Execute Workflow” trigger and enable “Continue On Fail” so the workflow runs even if verification fails, allowing you to log the incoming header.

3.4 Manual Signature Validation (Custom Logic)

Use a **Function** node after the Webhook to recompute and compare the signature when you need custom behavior (e.g., multiple secrets, timing‑attack mitigation).

Load crypto and read inputs

const crypto = require('crypto');
const secret = process.env.SECRET_WEBHOOK;
const received = $json["x-n8n-signature"];   // header captured via Set node
const body = $json["rawBody"];               // raw request body from webhook

Compute the expected HMAC

const expected = crypto
  .createHmac('sha256', secret)
  .update(body, 'utf8')
  .digest('hex');

Validate and abort on mismatch

if (expected !== received) {
  throw new Error('Signature mismatch');
}
return items;

4. Advanced Troubleshooting Checklist

If you encounter any
n8n http node invalid json response error
resolve them before continuing.

  • [ ] View raw request – Click “Show Full Request” in the execution log; confirm header name/value.
  • [ ] Confirm environment variable – Use a Set node with {{$env.SECRET_WEBHOOK}} and inspect (mask in logs).
  • [ ] Check proxy configuration – For Nginx: proxy_set_header X-n8n-signature $http_x_n8n_signature;
  • [ ] Validate encoding – Ensure payload is UTF‑8; re‑encode if necessary.
  • [ ] Guard against replay attacks – If the provider includes a timestamp (e.g., Stripe), add a Function node to reject signatures older than 5 minutes.
  • [ ] Log only non‑secret data – Never log the secret or full signature in production logs.

5. Production‑Grade EEFA (Experience, Expertise, Freshness, Authority) Notes

Concern Recommended Fix
Secret leakage Store in n8n Environment Variables or an external secret manager (AWS Secrets Manager, HashiCorp Vault).
Header stripping by CDN Whitelist x-n8n-signature (e.g., Cloudflare → Transform Rules → Header Modification).
Replay attacks Add a timestamp check (see Section 4) and reject signatures older than a configurable window.
Error handling Use an **Error Workflow** to capture signature failures and send alerts (e.g., Slack webhook).
Audit trail Write a lightweight entry to PostgreSQL or MongoDB with requestId, status, and timestamp (exclude the signature value).

 


Conclusion

Validating webhook signatures in n8n is a straightforward three‑step process: enable the signature option, send a correctly computed x-n8n-signature header, and ensure the header reaches n8n unchanged. By storing the secret in an environment variable, handling alternate header names with a Set node, and optionally performing manual validation, you eliminate the “Missing signature” error while keeping your workflow production‑ready, secure, and auditable.

All instructions target the latest stable n8n version (January 2026). Adjust paths for self‑hosted Docker deployments as needed.

Leave a Comment

Your email address will not be published. Required fields are marked *