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 →
{
"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.
cryptohttpHeaderAuthopenAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
> 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 →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Remi 1.1. Uses lmChatOpenAi, memoryPostgresChat, openAi, postgres. Webhook trigger; 89 nodes.
'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
IA Professor de Espanhol de Tecnologia (Corrigido v2). Uses supabase, crypto, agent, lmChatOpenAi. Webhook trigger; 18 nodes.
IA Professor de Espanhol de Tecnologia. Uses supabase, crypto, agent, lmChatOpenAi. Webhook trigger; 18 nodes.
n8n Chat Demo (GitHub) copy. Uses agent, lmChatOpenAi, memoryBufferWindow, crypto. Webhook trigger; 12 nodes.