This workflow corresponds to n8n.io template #8906 — we link there as the canonical source.
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": "vhGeQ894g6ZrApne",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Validate GitHub Webhook Secret",
"tags": [],
"nodes": [
{
"id": "d46d3d2c-39ae-4e7d-9c27-a47ea2f36cc2",
"name": "Respond 200 OK",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
752,
-80
],
"parameters": {
"options": {
"responseCode": 200
},
"respondWith": "noData"
},
"typeVersion": 1.4
},
{
"id": "6cfacb26-0472-4021-9060-62a5b67e3c8b",
"name": "Respond 401 Unauthorized",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
752,
96
],
"parameters": {
"options": {
"responseCode": 401
},
"respondWith": "noData"
},
"typeVersion": 1.4
},
{
"id": "e8683705-1757-4f3a-a332-9c68ee505cf8",
"name": "GitHub Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
-96,
0
],
"parameters": {
"path": "github-test",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2.1
},
{
"id": "4dea131c-2c72-4d67-a8b8-c9aff6c4ac1a",
"name": "Compute HMAC256",
"type": "n8n-nodes-base.crypto",
"position": [
208,
0
],
"parameters": {
"type": "SHA256",
"value": "={{ JSON.stringify($json.body) }}",
"action": "hmac",
"secret": "=your_github_secret_here",
"dataPropertyName": "=signature-256"
},
"typeVersion": 1
},
{
"id": "98a2788a-081e-4f59-8845-08d28fb7f9c9",
"name": "Validate HMAC256",
"type": "n8n-nodes-base.if",
"position": [
416,
0
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "80e6b785-15d2-4f32-94e6-fcd7942fb2e4",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json['signature-256'] }}",
"rightValue": "={{ $json.headers['x-hub-signature-256'].split('=').pop() }}"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "d61e551c-0b5a-4b3a-a7de-035d0be495d0",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
160,
-368
],
"parameters": {
"color": 7,
"width": 520,
"height": 780,
"content": "## 1. Compute the HMAC256 for the webhook body and compare to provided HMAC256 value\n[Read more about validating GitHub webhook deliveries](https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries)\n\nWhen a secret is provided during GitHub webhook setup, a `x-hub-signature-256` header is added to the webhook. This header contains the HMAC (Hash-based Message Authentication Code). Validating this signature guarantees both the data integrity and authenticity of the message.\n\nThe [n8n Crypto node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.crypto/#hmac-parameters) has the capability of computing the HMAC-256 value given a message and a secret and store the result into a field. "
},
"typeVersion": 1
},
{
"id": "b075a191-631f-4145-a585-00fea49e07f1",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
704,
-368
],
"parameters": {
"color": 7,
"width": 520,
"height": 780,
"content": "## 2. Acknowledge message validity with GitHub server\n\nUse the response nodes to communicate the result of the HMAC256 validation back to GitHub:\n* \u2705 Return 200 OK if the computed signature matches the one provided in the `x-hub-signature-256` header. This confirms the message is authentic and allows the workflow to continue.\n* \u274c Return 401 Unauthorized if the signatures do not match. This stops the workflow and signals GitHub that the request is invalid. \n"
},
"typeVersion": 1
},
{
"id": "390aeb5b-8bcc-4591-bea8-550c5f1be475",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1248,
-368
],
"parameters": {
"color": 7,
"width": 520,
"height": 780,
"content": "## 3. Continue with remainder of workflow...\n\nOnce the webhook request has been verified as authentic, you can safely proceed with your workflow. This is where you should insert your own business logic \u2014 for example:\n* Sending notifications\n* Logging events\n* Any other GitHub-related automation\n\nReplace the placeholder node after the 200 OK response with your own custom steps. You can also use the Set node to define variables or extract data from the webhook payload for use in downstream nodes."
},
"typeVersion": 1
},
{
"id": "41239b01-a07c-4dc2-a169-c1aca34b32df",
"name": "Get the profile of a repository",
"type": "n8n-nodes-base.github",
"position": [
1408,
-80
],
"parameters": {
"owner": {
"__rl": true,
"mode": "url",
"value": "={{ $json.body.repository.owner.html_url }}"
},
"resource": "repository",
"operation": "getProfile",
"repository": {
"__rl": true,
"mode": "url",
"value": "={{ $json.body.repository.html_url }}"
}
},
"credentials": {
"githubApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.1
},
{
"id": "74a5a28c-2bd0-42e8-961b-2ef35d0c1b44",
"name": "Stop and Error",
"type": "n8n-nodes-base.stopAndError",
"position": [
976,
96
],
"parameters": {
"errorMessage": "HMAC256 signature doesn't match provided signature. Make sure that the GitHub webhook secret is identical to the secret stored in the 'Compute HMAC256' node. "
},
"typeVersion": 1
},
{
"id": "97a22928-bfe7-433e-b989-9ae5799edcd0",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-656,
-464
],
"parameters": {
"width": 460,
"height": 1280,
"content": "## Validate GitHub webhook signature using HMAC256\n\n### Use cases \n* Ensure that the calls to the workflow's webhook are (a) originating from the correct GitHub repository and (b) haven't been tampered with.\n\n### How it works\n* When a secret is provided in a GitHub webhook configuration, a `x-hub-signature-256` header is added to the webhook.\n* `Compute HMAC256` computes the HMAC256 signature similarly to how it was computed by GitHub.\n* `Validate HMAC256` tests for the equality of the computed value and the value provided by the header.\n * If the values are equal then 200 is returned to GitHub and the workflow continues\n * If the values are NOT equal then 401 is returned and the workflow ends. \n * __Note:__ The `Stop and Error` step is optional and can be removed. Removing it means that the workflow completes successfully while still returning 401 to GitHub. This means that you will not be able to easily track malicious or incorrect calls to your webhook from n8n. \n\n### How to use\n* Add the steps (1) and (2) of the workflow to your current workflow receiving webhook calls from GitHub.\n* Update the `Secret` field in the `Compute HMAC256` node with the same value as the secret stored in the `Secret` field in the GitHub webhook definition. \n\n### Requirements\n* GitHub account and repository. \n* GitHub webhook setup with a `Secret` key. Key can be of any length and should be generated with a key or password generator. \n\n### Who\u2019s it for\nDevelopers or DevOps engineers who want to ensure secure webhook communication between GitHub and n8n.\n\n### How to customize the workflow\n* This is a building block for your own workflow. If you use this workflow as a base, replace step (3) with your own business logic. \n* You can modify the Stop and Error node to log unauthorized requests or trigger alerts. \n\n\n### \u26a0\ufe0f Warning\nThe secret is stored in plain text in the workflow. You should take this into consideration if the workflow is committed to source control or shared in any other way.\n\n### Need Help?\nReach out on [LinkedIn](https://www.linkedin.com/in/ytkaczyk/) or Ask in the [Forum](https://community.n8n.io/)!\n"
},
"typeVersion": 1
}
],
"active": true,
"settings": {
"timezone": "America/Denver",
"callerPolicy": "workflowsFromSameOwner",
"executionOrder": "v1"
},
"versionId": "0ec47ca5-fa4e-43f3-a827-85fe278f10af",
"connections": {
"GitHub Webhook": {
"main": [
[
{
"node": "Compute HMAC256",
"type": "main",
"index": 0
}
]
]
},
"Respond 200 OK": {
"main": [
[
{
"node": "Get the profile of a repository",
"type": "main",
"index": 0
}
]
]
},
"Compute HMAC256": {
"main": [
[
{
"node": "Validate HMAC256",
"type": "main",
"index": 0
}
]
]
},
"Validate HMAC256": {
"main": [
[
{
"node": "Respond 200 OK",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond 401 Unauthorized",
"type": "main",
"index": 0
}
]
]
},
"Respond 401 Unauthorized": {
"main": [
[
{
"node": "Stop and Error",
"type": "main",
"index": 0
}
]
]
},
"Get the profile of a repository": {
"main": [
[]
]
}
}
}
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.
githubApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Ensure that the calls to the workflow's webhook are (a) originating from the correct GitHub repository and (b) haven't been tampered with. When a secret is provided in a GitHub webhook configuration, a header is added to the webhook. computes the HMAC256 signature similarly to…
Source: https://n8n.io/workflows/8906/ — 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.
Claude Config Sync Webhook. Uses github, respondToWebhook, crypto, stopAndError. Webhook trigger; 10 nodes.
This n8n workflow template uses community nodes and is only compatible with the self-hosted version of n8n.
AIDP - Main Workflow v3. Uses executeCommand, github, jira. Webhook trigger; 12 nodes.
This n8n workflow template uses community nodes and is only compatible with the self-hosted version of n8n.
Sync Zendesk Tickets With Subsequent Comments To Github Issues. Uses zendesk, github. Webhook trigger; 7 nodes.