AutomationFlowsGeneral › Verify HMAC Signature

Verify HMAC Signature

Original n8n title: Hmac Verify

hmac-verify. Uses executeWorkflowTrigger. Event-driven trigger; 4 nodes.

Event trigger★★★★☆ complexity4 nodesExecute Workflow Trigger
General Trigger: Event Nodes: 4 Complexity: ★★★★☆ Added:

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "hmac-verify",
  "name": "hmac-verify",
  "nodes": [
    {
      "parameters": {},
      "id": "start",
      "name": "On Sub-Workflow Call",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1,
      "position": [
        240,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// HMAC-SHA256 Verification (R-003, R-014)\n// Centralized sub-workflow \u2014 called by all webhook workflows\n// Constitution II: Threat-model driven (unauthorized webhook callers)\n// 019: Reads secret from own Static Data (not $env) for N8N_BLOCK_ENV_ACCESS_IN_NODE=true\n\nconst crypto = require('crypto');\n\n// Read HMAC secret from this workflow's Static Data\nconst staticData = $getWorkflowStaticData('global');\nconst secret = staticData.webhookSecret;\nif (!secret) {\n  return [{ json: { verified: false, error: 'HMAC secret not configured \u2014 set webhookSecret in hmac-verify Static Data' } }];\n}\n\n// Read headers and body from the calling workflow's input\nconst inputData = $input.all()[0].json;\nconst signature = inputData.headers?.['x-signature'] || '';\nconst timestamp = inputData.headers?.['x-timestamp'] || '';\nconst rawBody = inputData.rawBody || JSON.stringify(inputData.body || {});\n\n// Replay protection: timestamp must be within 5 minutes\nconst now = Math.floor(Date.now() / 1000);\nconst requestTime = parseInt(timestamp, 10);\nif (isNaN(requestTime) || Math.abs(now - requestTime) > 300) {\n  return [{ json: { verified: false, error: 'Timestamp expired or invalid (>5 min drift)' } }];\n}\n\n// Compute expected signature\nconst expectedSig = 'sha256=' + crypto\n  .createHmac('sha256', secret)\n  .update(rawBody, 'utf8')\n  .digest('hex');\n\n// Constant-time comparison\nconst sigBuffer = Buffer.from(signature);\nconst expectedBuffer = Buffer.from(expectedSig);\n\nif (sigBuffer.length !== expectedBuffer.length || !crypto.timingSafeEqual(sigBuffer, expectedBuffer)) {\n  return [{ json: { verified: false, error: 'HMAC signature mismatch' } }];\n}\n\nreturn [{ json: { verified: true, body: inputData.body } }];"
      },
      "id": "hmac-code",
      "name": "Verify HMAC",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        460,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "76f4d3e9-e1c2-4711-963b-b095d2311ba4",
              "leftValue": "={{ $json.verified }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "check-result",
      "name": "Is Verified?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        680,
        300
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ error: 'Unauthorized', details: $json.error }) }}",
        "options": {
          "responseCode": 401
        }
      },
      "id": "reject",
      "name": "Reject 401",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        900,
        420
      ],
      "notes": "Returns 401 for failed HMAC verification"
    }
  ],
  "connections": {
    "On Sub-Workflow Call": {
      "main": [
        [
          {
            "node": "Verify HMAC",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verify HMAC": {
      "main": [
        [
          {
            "node": "Is Verified?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Verified?": {
      "main": [
        [],
        [
          {
            "node": "Reject 401",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "meta": {
    "notes": "HMAC-SHA256 verification sub-workflow. Called by all webhook workflows as first step. R-014: Single source of truth for verification logic. Constitution II: Proves caller identity + request integrity + replay protection."
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

hmac-verify. Uses executeWorkflowTrigger. Event-driven trigger; 4 nodes.

Source: https://github.com/traylorre/openclaw-mac/blob/d5ef2bd70e230b1877d7165d35c2e27947b269e0/workflows/hmac-verify.json — original creator credit. Request a take-down →

More General workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

General

Agendamiento. Uses n8n-nodes-evolution-api, redis, dataTable, executeWorkflowTrigger. Event-driven trigger; 60 nodes.

N8N Nodes Evolution Api, Redis, Data Table +2
General

Prevent concurrent workflow runs using Redis. Uses executeWorkflowTrigger, manualTrigger, stickyNote, executeWorkflow. Event-driven trigger; 43 nodes.

Execute Workflow Trigger, Redis, Stop And Error
General

This workflow sets a small "lock" value in Redis so that only one copy of a long job can run at the same time. If another trigger fires while the job is still busy, the workflow sees the lock, stops e

Execute Workflow Trigger, Redis, Stop And Error
General

Reputation Engine — Site Refresh. Uses httpRequest, executeWorkflowTrigger. Event-driven trigger; 35 nodes.

HTTP Request, Execute Workflow Trigger
General

Using n8n a lot?

Execute Workflow Trigger, XML, Move Binary Data +1