AutomationFlowsAI & RAG › Secure AI Agent Webhook with HMAC & Replay Protection

Secure AI Agent Webhook with HMAC & Replay Protection

Original n8n title: Secure AI Agent Webhook with Hmac, Replay Protection, and Openai Gpt-5

ByDataki @dataki on n8n.io

> I am not a cybersecurity expert. This workflow was built through research and with the assistance of an LLM (Claude Opus 4.6). While it implements well-established security patterns (HMAC-SHA256, timing-safe comparison, replay protection, strict payload validation), please…

Webhook trigger★★★★☆ complexityAI-powered16 nodesAgentOpenAI ChatCrypto
AI & RAG Trigger: Webhook Nodes: 16 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #14486 — we link there as the canonical source.

This workflow follows the Agent → OpenAI Chat recipe pattern — see all workflows that pair these two integrations.

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": "",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Secure AI Agent Webhook with HMAC Signature & Strict JSON Validation",
  "tags": [],
  "nodes": [
    {
      "id": "90b338c9-93c3-4864-a79f-1bde8238ca13",
      "name": "If1",
      "type": "n8n-nodes-base.if",
      "position": [
        1520,
        -16
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "6879b197-7c2c-4aa4-887b-665e4af608ad",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.valid }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "745d250f-f77d-4ae3-877a-ce74b44a3913",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        2000,
        -32
      ],
      "parameters": {
        "text": "={{ $json.data.prompt }}",
        "options": {
          "enableStreaming": true
        },
        "promptType": "define"
      },
      "typeVersion": 3.1
    },
    {
      "id": "af71ad64-39a6-405d-8be3-44cc1c2014df",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        2000,
        160
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-5-mini"
        },
        "options": {},
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "bd793b40-62b1-4868-9881-5db761841a31",
      "name": "Response to webhook : Forbidden",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1104,
        80
      ],
      "parameters": {
        "options": {
          "responseCode": 403
        },
        "respondWith": "noData"
      },
      "typeVersion": 1.5
    },
    {
      "id": "44b8ee9c-66fe-4b8c-835d-c5778151a9bc",
      "name": "Bad Request",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1728,
        64
      ],
      "parameters": {
        "options": {
          "responseCode": 400
        },
        "respondWith": "noData"
      },
      "typeVersion": 1.5
    },
    {
      "id": "a61610f9-aff7-4bd4-a397-d7338c312959",
      "name": "Strict Payload Validation",
      "type": "n8n-nodes-base.code",
      "position": [
        1376,
        -16
      ],
      "parameters": {
        "jsCode": "// \ud83d\udee1\ufe0f 1. Secure JSON parsing\nlet data;\ntry {\n  data = JSON.parse($json.rawBody);\n} catch (e) {\n  return [{ json: { valid: false, error: 'Invalid or malformed JSON' } }];\n}\n\n// \ud83c\udfaf 2. Required field check\nif (!data.prompt) {\n  return [{ json: { valid: false, error: \"Missing required field: 'prompt'\" } }];\n}\n\n// \ud83d\udd12 3. Strict whitelist filtering against parameter injection\nconst allowedKeys = ['prompt'];\nfor (const key of Object.keys(data)) {\n  if (!allowedKeys.includes(key)) {\n    return [{ json: { valid: false, error: `Unexpected field: '${key}'` } }];\n  }\n}\n\n// \u2705 4. Validation passed \u2014 forward clean data\nreturn [{ json: { valid: true, data } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "3e303f53-a9d8-4002-b190-1ff44a8ebb0e",
      "name": "Crypto",
      "type": "n8n-nodes-base.crypto",
      "position": [
        592,
        0
      ],
      "parameters": {
        "value": "={{ $json.xTimestamp + '.' + $json.rawBody }}",
        "action": "hmac"
      },
      "credentials": {
        "crypto": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "f89af9d6-ced7-45f5-b7cd-f77f720cd91f",
      "name": "If2",
      "type": "n8n-nodes-base.if",
      "position": [
        912,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "f9163a1d-7b7b-49e3-916a-dd51d4628f0a",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.isValid }}",
              "rightValue": "={{ $json.headers[\"x-signature\"] }}"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "902cb118-861e-4f41-a663-0468475c3ac7",
      "name": "Timing-Safe HMAC Check",
      "type": "n8n-nodes-base.code",
      "position": [
        752,
        0
      ],
      "parameters": {
        "jsCode": "const crypto = require('crypto');\n\n// \ud83d\udee1\ufe0f 1. Validate timestamp freshness (5 min)\nconst timestamp = parseInt($json.xTimestamp, 10);\nconst now = Math.floor(Date.now() / 1000);\nif (!timestamp || Math.abs(now - timestamp) > 300) {\n  return [{ json: { isValid: false, reason: 'Timestamp expired or missing' } }];\n}\n\n// \ud83d\udd10 2. Timing-safe comparison of HMAC signatures\nconst computedHmac = $json.data;\nconst receivedSignature = $json.xSignature || '';\nlet isValid = false;\n\nif (computedHmac && receivedSignature) {\n  const bufA = Buffer.from(computedHmac, 'utf8');\n  const bufB = Buffer.from(receivedSignature, 'utf8');\n\n  if (bufA.length === bufB.length) {\n    isValid = crypto.timingSafeEqual(bufA, bufB);\n  } else {\n    // Constant-time compare against itself to avoid leaking length info\n    crypto.timingSafeEqual(bufA, bufA);\n    isValid = false;\n  }\n}\n\n// \u2705 3. Pass through validated data for downstream nodes\nreturn [{\n  json: {\n    isValid,\n    rawBody: $json.rawBody\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "1fb6a51e-3c4b-4593-924e-d5449238e023",
      "name": "Extract rawBody",
      "type": "n8n-nodes-base.code",
      "position": [
        288,
        0
      ],
      "parameters": {
        "jsCode": "// Extract raw body and required security headers from webhook\nconst binaryData = items[0].binary.data;\nconst rawBody = Buffer.from(binaryData.data, 'base64').toString('utf8');\nconst headers = items[0].json.headers;\n\nreturn [{\n  json: {\n    rawBody,\n    xTimestamp: headers['x-timestamp'],\n    xSignature: headers['x-signature']\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "d65b3d16-a2e8-4e9d-a823-1c42244ee0b6",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -752,
        -240
      ],
      "parameters": {
        "width": 640,
        "height": 672,
        "content": "\n# Secure AI Agent Webhook\n\n### **\u26a0\ufe0f Disclaimer: I am not a cybersecurity expert.**\n> This workflow was built through research and with the assistance of an LLM (Claude 3.5 Sonnet / Opus). While it implements well-established security patterns (HMAC-SHA256, timing-safe comparison, replay protection, strict payload validation), please review the logic carefully and ensure it meets your own security requirements before deploying it in production.\n\n## How it works\nThis workflow provides an enterprise-grade, highly secure entry point for AI Agents. It receives raw JSON payloads via a Webhook and performs rigorous security validations before processing. \n\nIt checks for a valid Header Auth token, protects against replay attacks by verifying an `X-Timestamp`, and computes a SHA-256 HMAC signature against the raw payload to ensure byte-for-byte integrity. Finally, it strictly validates the JSON schema to prevent parameter injection before passing the clean prompt to the AI Agent.\n\n### Setup\n1. Configure the **Webhook** node with your HTTP Header Auth credentials.\n2. Add a **Crypto** credential to the Crypto node containing your secure shared HMAC secret (generate via `openssl rand -hex 32`).\n3. Configure the **OpenAI Chat Model** with your OpenAI API key.\n4. Send requests to the Webhook URL including `X-Timestamp` and `X-Signature` headers.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "76d6e9c3-d944-4f84-a1bb-e16ef2a7a179",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        0,
        0
      ],
      "parameters": {
        "path": "7ca64bd2",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "streaming",
        "authentication": "headerAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "76ab6a91-5b47-405e-a812-0036c2e46830",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        -128
      ],
      "parameters": {
        "color": 7,
        "width": 544,
        "height": 272,
        "content": "## 1. Webhook & Extraction\nReceives raw body payload and extracts the timestamp and signature security headers."
      },
      "typeVersion": 1
    },
    {
      "id": "187f4278-cb48-4277-947b-3254d55d2da3",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        -128
      ],
      "parameters": {
        "color": 7,
        "width": 720,
        "height": 480,
        "content": "## 2. HMAC & Replay Protection\nComputes a SHA-256 HMAC and performs a timing-safe signature comparison. Returns a 403 Forbidden if invalid or expired."
      },
      "typeVersion": 1
    },
    {
      "id": "c0e73c97-bd95-4bb4-b851-f149aabf1cb5",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1344,
        -128
      ],
      "parameters": {
        "color": 7,
        "width": 512,
        "height": 480,
        "content": "## 3. Strict Payload Validation\nSafely parses JSON and applies whitelist filtering to prevent injection. Returns a 400 Bad Request if unauthorized keys are found."
      },
      "typeVersion": 1
    },
    {
      "id": "ce8ea4f4-7964-4766-beab-afa6347041d7",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1888,
        -128
      ],
      "parameters": {
        "color": 7,
        "width": 512,
        "height": 480,
        "content": "## 4. AI Agent \nSecurely processes the sanitized and verified prompt."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "820af296-9948-4549-9b28-d44f0d5cc409",
  "connections": {
    "If1": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Bad Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If2": {
      "main": [
        [
          {
            "node": "Strict Payload Validation",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Response to webhook : Forbidden",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Crypto": {
      "main": [
        [
          {
            "node": "Timing-Safe HMAC Check",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook": {
      "main": [
        [
          {
            "node": "Extract rawBody",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent": {
      "main": [
        []
      ]
    },
    "Extract rawBody": {
      "main": [
        [
          {
            "node": "Crypto",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Timing-Safe HMAC Check": {
      "main": [
        [
          {
            "node": "If2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Strict Payload Validation": {
      "main": [
        [
          {
            "node": "If1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

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

About this workflow

&gt; I am not a cybersecurity expert. This workflow was built through research and with the assistance of an LLM (Claude Opus 4.6). While it implements well-established security patterns (HMAC-SHA256, timing-safe comparison, replay protection, strict payload validation), please…

Source: https://n8n.io/workflows/14486/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

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

AI & RAG

Remi 1.1. Uses lmChatOpenAi, memoryPostgresChat, openAi, postgres. Webhook trigger; 89 nodes.

OpenAI Chat, Memory Postgres Chat, OpenAI +7
AI & RAG

'Elena AI' is a powerful n8n workflow that transforms your automation platform into a full-fledged, multi-agent AI hub. 🤖✨ By combining Redis state management with specialized “tool” sub-workflows, yo

Redis, HTTP Request, Supabase +7
AI & RAG

IA Professor de Espanhol de Tecnologia (Corrigido v2). Uses supabase, crypto, agent, lmChatOpenAi. Webhook trigger; 18 nodes.

Supabase, Crypto, Agent +4
AI & RAG

IA Professor de Espanhol de Tecnologia. Uses supabase, crypto, agent, lmChatOpenAi. Webhook trigger; 18 nodes.

Supabase, Crypto, Agent +4
AI & RAG

n8n Chat Demo (GitHub) copy. Uses agent, lmChatOpenAi, memoryBufferWindow, crypto. Webhook trigger; 12 nodes.

Agent, OpenAI Chat, Memory Buffer Window +1