GitHub Webhooks Tutorial
Tags: devops, tutorial, github, webhook
Published: 2021-10-21 18:44:27

---
title: GitHub Webhooks Tutorial
published: true
description: In this tutorial, we explore GitHub webhooks by demonstrating a simple use case
tags: #devops #tutorial #github #webhook
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/38pib1kd35axg574kuwi.gif
canonical_url: https://hookdeck.com/guides/platforms/post/tutorial-github-webhooks
---

## Introduction

As one of the biggest code hosting platforms available today, GitHub provides numerous ways for developers to integrate with the platform. One of those integration options is GitHub webhooks.

In this article, we are going to explore GitHub webhooks. We will look at what a GitHub webhook is, and how to set it up on our GitHub account. Further, we will explore a sample API that receives and logs webhook events. This API will run on our local development environment, thus we will be receiving the webhooks on our local machine. However, if you have a local API you would rather use, feel free to follow along with the article.

## What is GitHub Webhooks?

GitHub Webhooks gives developers the ability to integrate with the GitHub platform.

Developers can subscribe to events taking place on GitHub, such as push events that occur when code is pushed to a repository, and respond to the event with an action.

The response action can be anything: making a database entry in an external application, sending an email, or triggering a deployment process, just to name a few. Actions you can perform in response to events on GitHub are limited only by your imagination.

When a subscribed event occurs on GitHub, GitHub triggers an HTTP POST request to the defined destination. This destination is specified as an HTTP URL, which is the endpoint to be called whenever the event occurs. This is known as the webhook URL. The endpoint handler at the webhook URL handles the action to be performed in response to the event.

Along with the request, GitHub also sends the payload of data about the event that triggered the webhook. Information contained in this payload can be used for the action on the endpoint.

## Tutorial: How to set up GitHub Webhooks

To begin the tutorial, let's take a look at the steps involved:

- Clone the sample Node.js API for receiving GitHub webhooks on your development machine
- Generate a webhook URL using the Hookdeck CLI
- Register for a webhook on GitHub
- Receive and inspect GitHub webhooks locally
- Make some commits and view logs

### Clone a demo API server for receiving GitHub webhooks

As described earlier, GitHub webhooks need to be sent to an endpoint on your API.

If you already have a server running with a `POST` endpoint to receive the webhook request, you can skip this section. All you need to do is to take note of the port that your local API is running and also the endpoint to receive webhooks. Substitute these values as you follow this exercise.

If you do not have a local API, you can use a [Node.js](https://nodejs.org/) sample API available on the [Hookdeck GitHub repository](https://github.com/hookdeck/nodejs-webhook-server-example). Follow the instructions below to set it up.

Clone the repository by running the following command:

```bash
git clone --single-branch --branch github-webhooks https://github.com/hookdeck/nodejs-webhook-server-example.git
```

Navigate to the root of the project and install the required dependencies by running the following commands:

```bash
cd nodejs-webhook-server-example
npm install
```

When the installation completes, you can then run the Node.js server with the following command:

```bash
npm start
```

This will boot up the API application and print a message to the screen indicating that the API is now running and listening for connections on port `1337`.

We are using two endpoints in this project.

- `/log-github-webhook`: This is the endpoint that will be receiving the GitHub webhook and logging it into an in-memory database. It logs a simple object containing a subset of the information from the webhook payload.
- `/fetch-webhooks-logs`: This endpoint can be called to retrieve a collection of the logged webhook data.

### Get the webhook URL for GitHub

Endpoints on locally running servers cannot receive GitHub webhooks; a publicly accessible endpoint is required and this is where the Hookdeck CLI comes in. The [Hookdeck CLI](https://hookdeck.com/cli) is built specifically for working with webhooks, and helps tunnel external HTTP requests into your local development environment by providing you with a publicly accessible HTTPS URL. You can also inspect the headers and payloads of your webhooks, as you will see later on in this tutorial.

Visit Hookdeck's [CLI documentation](https://hookdeck.com/cli) to install and set up the tool on your operating system. For macOS users, you can run the following command to install the CLI tool:

```bash
brew install hookdeck/hookdeck/hookdeck
```

If you're using the Windows operating system, use the following command to install the CLI tool:

```bash
scoop bucket add hookdeck https://github.com/hookdeck/scoop-hookdeck-cli.git
scoop install hookdeck
```

Once the setup process is complete, the next step is to use the CLI to generate a webhook URL that points to the running API application. To do this, run the following command (note: replace the port `1337` value with the port number on which your API is running if you're not using the sample project):

```bash
hookdeck listen 1337
```

This command starts an interactive session where the CLI collects information about the endpoint you're about to create. Below are the questions and the answers you should supply to each question. Ensure to hit the `Enter` key after each answer.

- **What source should you select?** Ans: select ***Create new source***
- **What should your new source label be?** Ans: type the text ***Github***
- **What path should the webhooks be forwarded to (i.e.: /webhooks)**? Ans: type ***/log-github-webhook*** (If you're using your own custom server, replace this value with your endpoint)
- **What's the connection label (i.e.: My API)?** Ans: type ***My Github Response Server***

With this information, the CLI will begin the process of generating the URL and once it's done, you will see the URL printed to the screen and the CLI indicating that it is ready to receive requests.

![CLI Ready](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0g0r04dn23mj2i3tyhso.png)

**Note:** You will need to use the guest `Login URL` link in the console to access the dashboard. Copy and paste this into your browser to begin a guest login session.

### Set up webhook on GitHub

Next, you will need to subscribe to a GitHub webhook. Navigate to your repository of choice (this should be a repository you own) and go to **Settings → Webhooks**. On the **Webhooks** page, click on the `Add webhook` button on the top right-hand corner.

On the webhook form displayed, paste the webhook URL generated by the Hookdeck CLI into the `Payload URL` field.

Fill the remaining fields as follows:

- **Content type:** Select `application/json` so that you can receive the payload as a JSON object.
- **Secret:** You can leave this blank, but for the purpose of this tutorial enter `1234ABCD`.
- **SSL verification:** Leave this as the default option of `Enable SSL verification`.
- **Which events would you like to trigger this webhook?** This is the point where you subscribe for a GitHub event on your repository. For this tutorial, select the `Just the push event` option, as we are only subscribing to the `push` event. You can either subscribe for all events or a subset of the events using the other two options.
- **Active:** Leave this checked to receive event details when the GitHub webhook is triggered.

See the complete webhook form below:

![Add Webhook](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e1zigz6cuwftmx7t4nww.png)

Click the `Add webhook` button to complete the process.

With this setup, any time you push code to your repository, a webhook request will be fired to the specified webhook URL.

### Receive and inspect GitHub webhooks and payload

Immediately after you complete registration for a webhook in the step above, a `ping` webhook request will be fired to your webhook URL. Because we are using the Hookdeck CLI, we would already see the `ping` webhook request logged on the terminal where the Hookdeck CLI is running, as shown below:

![CLI Webhook Entry](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bicm1na0m86po3kz1nyt.png)

Here we can see that we have received a `POST` request with a `201` status code indicating that a new entity was created on our server; in other words, a webhook object was logged. 

To view details of the webhook request, its headers, and payload, copy the Hookdeck dashboard URL printed along with your webhook request details on the CLI and load it in your browser.

You will see a page similar to the one below:

![Event Page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p8go7brms28ldfrxaeiq.png)

On this page, you can go through and inspect all the data that came with your webhook request. For example, the `Headers` section is expanded in the image below:

![Event Headers](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/73hny5yxqw7b82aq7xc6.png)

You can also view all that is contained in the webhook request payload by expanding the `Body` section as shown below:

![Event Body](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/udxunnadscfd0hcl1y6f.png)

With this setup, you get full and clear visibility into your webhook requests and you will be able to monitor and quickly troubleshoot your webhooks when any failure occurs.

### View Application webhook logs

To check that the webhook information is being logged, make a few commits to your GitHub project. You should see webhook event entries in the terminal where your Hookdeck CLI session is running. Now visit the endpoint `/fetch-webhooks-logs`, where you should see a couple of log entries similar to the image below:

![Webhook Logs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lbbpp1tmoebq98odwkds.png)

As seen above, we are logging the `repo`, `author`, and `timestamp` of the commit. Ignore the first entry as this is simply a test entry so that the application database does not start empty.

## GitHub webhooks verification

A publicly accessible endpoint, just like the one being used as your webhook URL, can receive requests from anyone. This situation makes your endpoint vulnerable, as ill-intentioned individuals or bots can easily spoof requests imitating GitHub to dump irrelevant data into your system or manipulate your application.

You should verify the requests hitting your webhook URL to ascertain that they are from GitHub. GitHub helps you achieve this using the token secret we set in the form in an earlier step.

GitHub uses this token to create a hash signature with each payload. This hash signature is included with the headers of each request as `X-Hub-Signature-256`.

With this signature, you can validate your payloads. GitHub uses the [HMAC](https://en.wikipedia.org/wiki/HMAC) algorithm to compute the hash and it is the same algorithm you will use to implement the validation on your server. 

At the moment, our project is not enforcing this check but the code can be found commented out as shown below:

```js
//Validate payload
/* function validatePayload(req, res, next) {

    if(req.method == "POST"){
        if (!req.rawBody) {
            return next('Request body empty')
        }
    
        const sig = Buffer.from(req.get(sigHeaderName) || '', 'utf8')
        const hmac = crypto.createHmac(sigHashAlg, secret)
        const digest = Buffer.from(sigHashAlg + '=' + hmac.update(req.rawBody).digest('hex'), 'utf8');
    
        if (sig.length !== digest.length || !crypto.timingSafeEqual(digest, sig)) {
            return next(`Request body digest (${digest}) did not match ${sigHeaderName} (${sig})`)
        }
    }

    return next()

}
app.use(validatePayload); */
```

From lines 10 to 12, you can see the validation variables defined, as shown below:

```js
const sigHeaderName = 'X-Hub-Signature-256';
const sigHashAlg = 'sha256';
const secret = "1234ABCD";
```

The `secret` variable is the key we set when creating our webhook. In a production environment, these values should be kept in environment variables.

You can uncomment the payload validation middleware to ensure that your webhook payload is validated against the API secret set.

For more information on securing your GitHub webhooks, you can check out the GitHub documentation [here](https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks).

## How do I disable a GitHub Webhook?

At the moment, there is no setting on a GitHub webhook configuration that disables a webhook. Some will suggest that you uncheck the `Active` parameter but this only stops the delivery of the webhook payload, it may not prevent the event itself from being fired.

The only way you can be sure you have disabled a webhook is by deleting it completely from your GitHub **Webhooks** page. This may seem a bit extreme if you only want to disable it temporarily.

With [Hookdeck](https://hookdeck.com/), you can use the `Pause` feature on the dashboard to temporarily stop your webhooks from being delivered. When you're ready to start receiving them once again, you can unpause the webhook.

## Conclusion

Webhooks are a fantastic offering by GitHub to help developers extend their integrations with the platform to more custom use cases. This enables the development of more robust applications that take advantage of events occurring on GitHub.

In this tutorial, you have learned how to set up and receive GitHub webhooks on your API endpoints. The tasks you can perform in response to these events are only limited by your imagination.

Happy coding!