N
n8n Store
Workflow Market
Tutorial - Creating a Secure Webhook

Tutorial - Creating a Secure Webhook

by lucaspeyrin0 views

Description

Categories

⚙️ Automation

Nodes Used

n8n-nodes-base.ifn8n-nodes-base.setn8n-nodes-base.filtern8n-nodes-base.webhookn8n-nodes-base.webhookn8n-nodes-base.splitOutn8n-nodes-base.stickyNoten8n-nodes-base.stickyNoten8n-nodes-base.stickyNoten8n-nodes-base.stickyNote
PriceGratuit
Views0
Last Updated11/28/2025
workflow.json
{
  "meta": {
    "instanceId": "e409ea34548a2afe2dffba31130cd1cf2e98ebe2afaeed2a63caf2a0582d1da0",
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "d776b55a-65fe-4e12-9071-58911fa9c5cc",
      "name": "Registered API Keys",
      "type": "n8n-nodes-base.set",
      "position": [
        160,
        520
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "2ab01b9f-473f-4f1b-8ddf-8d5a7b706323",
              "name": "registered_api_keys",
              "type": "array",
              "value": "[\n   {\n      \"user_id\":\"user_1\",\n      \"api_key\":\"test\"\n   },\n   {\n      \"user_id\":\"user_2\",\n      \"api_key\":\"sk-lihefoihz12121ZFzk124zehfAZJAOJZ14joEKe1h\"\n   }\n]"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "d20bdc9b-3020-4fa3-88c3-b6c3d5a585b2",
      "name": "API Key Identified",
      "type": "n8n-nodes-base.if",
      "position": [
        480,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "0e476976-504d-4d21-a5d1-849fe54d322f",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.user_id }}",
              "rightValue": "={{ $('Secured Webhook').item.json.headers['x-api-key'] }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "73ee78a3-9e0c-4f24-a05f-f860dc8fda88",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        120,
        -260
      ],
      "parameters": {
        "color": 3,
        "width": 300,
        "height": 420,
        "content": "### ⚙️ Key Verification Logic\n\nThis node takes the API key from the incoming request and asks our \"database\" (the second webhook) if it's valid.\n\n**In a real-world scenario, you would replace this and the nodes below with a single Database node (e.g., Supabase, Postgres) to perform the lookup.**"
      },
      "typeVersion": 1
    },
    {
      "id": "b34ad49e-351a-4f42-8336-d4300d442c50",
      "name": "Respond to Webhook (success)",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        700,
        -100
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={\n  \"status\": \"success\",\n  \"user_id\": \"{{ $json.user_id }}\"\n}"
      },
      "typeVersion": 1.4
    },
    {
      "id": "2da5855a-d54a-43f1-b4c5-3ff510a10bd3",
      "name": "Respond to Webhook (unauthorized)",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        700,
        100
      ],
      "parameters": {
        "options": {
          "responseCode": 401
        },
        "respondWith": "json",
        "responseBody": "{\n  \"error\": \"Please provide a valid x-api-key header.\"\n}"
      },
      "typeVersion": 1.4
    },
    {
      "id": "0b56b704-4dd6-490a-9998-f8eb2ef0a00e",
      "name": "Secured Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -60,
        0
      ],
      "webhookId": "bf0be3b1-f140-4bc5-9040-a0e71dd78661",
      "parameters": {
        "path": "tutorial/secure-webhook",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode",
        "authentication": "headerAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "id": "pDp6BhprTE7kfSQy",
          "name": "n8n Templates"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "7308010d-5050-4e5e-8c8b-c57194b88516",
      "name": "Check API Key",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        220,
        0
      ],
      "parameters": {
        "url": "={{ $env.WEBHOOK_URL + ($env.N8N_ENDPOINT_WEBHOOK ?? \"webhook\") }}/tutorial/secure-webhook/api-keys",
        "options": {},
        "sendBody": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "api_key",
              "value": "={{ $json.headers['x-api-key'] }}"
            }
          ]
        },
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "id": "pDp6BhprTE7kfSQy",
          "name": "n8n Templates"
        }
      },
      "typeVersion": 4.2,
      "alwaysOutputData": true
    },
    {
      "id": "88070916-27b2-42fb-8005-970b6d5a08fc",
      "name": "Find API Key",
      "type": "n8n-nodes-base.filter",
      "position": [
        600,
        520
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "526ec1b1-4f6d-41ea-b35a-1347c01aa03a",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.api_key }}",
              "rightValue": "={{ $('Get API Key').last().json.body.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 2.2,
      "alwaysOutputData": true
    },
    {
      "id": "2a06aaa0-1ac3-4750-9770-6eec7e9310a9",
      "name": "Get API Key",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -60,
        520
      ],
      "webhookId": "bf0be3b1-f140-4bc5-9040-a0e71dd78661",
      "parameters": {
        "path": "tutorial/secure-webhook/api-keys",
        "options": {},
        "responseMode": "lastNode",
        "authentication": "headerAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "id": "pDp6BhprTE7kfSQy",
          "name": "n8n Templates"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "3803f9b8-deec-4262-a76b-bfd72d572493",
      "name": "Split Out Users",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        380,
        520
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "registered_api_keys"
      },
      "typeVersion": 1
    },
    {
      "id": "d81a0dd5-9c90-4fee-a7ec-46e9aabb53a3",
      "name": "Test Secure Webhook",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -420,
        0
      ],
      "parameters": {
        "url": "={{ $env.WEBHOOK_URL + ($env.N8N_ENDPOINT_WEBHOOK ?? \"webhook\") }}/tutorial/secure-webhook",
        "method": "POST",
        "options": {},
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "x-api-key",
              "value": "test"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "id": "pDp6BhprTE7kfSQy",
          "name": "n8n Templates"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "ca63d58d-4683-4dbc-bd1e-6fd2724152f7",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -500,
        -180
      ],
      "parameters": {
        "color": 6,
        "width": 600,
        "height": 340,
        "content": "### ▶️ Public Endpoint & Tester\n\n*   **`Secured Webhook`**: This is your public-facing endpoint. It listens for requests containing an `x-api-key` header.\n*   **`Test Secure Webhook`**: Use this node to test the endpoint. Change the `x-api-key` header value to test valid and invalid keys."
      },
      "typeVersion": 1
    },
    {
      "id": "14afef1c-6a99-46f5-96e1-c536a9afde69",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -140,
        320
      ],
      "parameters": {
        "color": 7,
        "width": 1020,
        "height": 380,
        "content": "### 📦 Mock Database\n\nThese nodes simulate a database of users and their API keys.\n\n*   **`Get API Key`**: A private webhook that receives a key and checks it against the list.\n*   **`Registered API Keys`**: **EDIT THIS NODE** to add or remove the API keys you want to be considered valid. Each key should be unique to a user."
      },
      "typeVersion": 1
    },
    {
      "id": "12074ea9-65a9-4696-8c87-c77842f44467",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        440,
        -300
      ],
      "parameters": {
        "color": 7,
        "width": 440,
        "height": 580,
        "content": "#### ✅ Gatekeeper\n\nThis IF node checks the result from our \"database\".\n\n*   If a user was found for the given API key, it proceeds to the **success** response.\n*   If not, it sends a **401 Unauthorized** error."
      },
      "typeVersion": 1
    }
  ],
  "pinData": {
    "Get API Key": [
      {
        "body": {
          "api_key": "sk-lihefoihz12121ZFzk124zehfAZJAOJZ14joEKe1h"
        },
        "query": {},
        "params": {},
        "headers": {
          "via": "1.1 Caddy",
          "host": "api.ia2s.app",
          "accept": "application/json,text/html,application/xhtml+xml,application/xml,text/*;q=0.9, image/*;q=0.8, */*;q=0.7",
          "user-agent": "axios/1.8.3",
          "x-n8n-auth": "my-secret-n8n-webhooks-password",
          "content-type": "application/json",
          "content-length": "58",
          "accept-encoding": "gzip, compress, deflate, br",
          "x-forwarded-for": "192.168.80.1",
          "x-forwarded-host": "api.ia2s.app",
          "x-forwarded-proto": "https"
        },
        "webhookUrl": "https://api.ia2s.app/webhook/tutorial/secure-webhook/api-keys",
        "executionMode": "production"
      }
    ],
    "Secured Webhook": [
      {
        "body": {},
        "query": {},
        "params": {},
        "headers": {
          "via": "1.1 Caddy",
          "host": "api.ia2s.app",
          "accept": "application/json,text/html,application/xhtml+xml,application/xml,text/*;q=0.9, image/*;q=0.8, */*;q=0.7",
          "x-api-key": "sk-lihefoihz12121ZFzk124zehfAZJAOJZ14joEKe1h",
          "user-agent": "axios/1.8.3",
          "x-n8n-auth": "my-secret-n8n-webhooks-password",
          "content-length": "0",
          "accept-encoding": "gzip, compress, deflate, br",
          "x-forwarded-for": "192.168.80.1",
          "x-forwarded-host": "api.ia2s.app",
          "x-forwarded-proto": "https"
        },
        "webhookUrl": "https://api.ia2s.app/webhook/tutorial/secure-webhook",
        "executionMode": "production"
      }
    ]
  },
  "connections": {
    "Get API Key": {
      "main": [
        [
          {
            "node": "Registered API Keys",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check API Key": {
      "main": [
        [
          {
            "node": "API Key Identified",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Secured Webhook": {
      "main": [
        [
          {
            "node": "Check API Key",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out Users": {
      "main": [
        [
          {
            "node": "Find API Key",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "API Key Identified": {
      "main": [
        [
          {
            "node": "Respond to Webhook (success)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Webhook (unauthorized)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Registered API Keys": {
      "main": [
        [
          {
            "node": "Split Out Users",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

相关工作流