Author picture Fikayo Adepoju Oreoluwa

Tutorial for Setting Up GitHub Webhooks

Published


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 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.

Github Webhook Tutorial

How to set up GitHub Webhooks

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

  1. Clone the sample Node.js API for receiving GitHub webhooks on your development machine
  2. Generate a webhook URL using the Hookdeck CLI
  3. Register for a webhook on GitHub
  4. Receive and inspect GitHub webhooks locally
  5. 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 sample API available on the Hookdeck GitHub repository. Follow the instructions below to set it up.

Clone the repository by running the following command:

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:

cd nodejs-webhook-server-example
npm install

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

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.

EndpointDescription
/log-github-webhookThis 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-logsThis endpoint can be called to retrieve a collection of the logged webhook data.

Get the webhook URL

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 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 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:

brew install hookdeck/hookdeck/hookdeck

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

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):

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.

QuestionAnswer
What source should you select?select Create new source
What should your new source label be?type the text Github
What path should the webhooks be forwarded to (i.e.: /webhooks)?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)?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-new

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

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-github

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 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-event-entry-new

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-new

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-new

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

event-body-new

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:

webhooks-logs

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 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:

//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:

const sigHeaderName = "X-Hub-Signature-256";
const sigHashAlg = "sha256";
const secret = "ABCD1234";

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.

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, 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!