Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions integrations/alerts/webhooks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ In both cases we use the familiar Handlebars templating braces, i.e. `{{ }}` to
To avoid encoding, you can access your environment variables with triple brackets, i.e. `{{{USER_API_KEY}}}`
</Note>

A JSON payload template stays valid JSON when an inserted value contains a double quote or a line break: the value is escaped in the body we send. With `{{CHECK_NAME}}` a double quote arrives as `&quot;`, with `{{{CHECK_NAME}}}` as `\"`; a line break arrives as `\n` in both cases.

<AlertChannelSecrets />

You can use the following event-related variables in both URL and payload.
Expand Down Expand Up @@ -175,19 +177,19 @@ You can validate each webhook we deliver to your endpoint(s). Using the optional
1. Check if the webhook was sent by Checkly.
2. Check if the payload was not altered in any way during transmission.

When you create a webhook secret, we proceed to use that secret token to cryptographically sign the webhook payload using the SHA256 hash algorithm. We add the resulting hash to the HTTP header `x-checkly-signature` on each webhook.
When you create a webhook secret, we use it to sign each webhook: the HTTP header `x-checkly-signature` contains the HMAC-SHA256 of the raw request body, keyed with your secret and hex-encoded. The signature covers the exact bytes we send, for JSON and plain text bodies alike.

On the receiving end, you can then use the value of the `x-checkly-signature` header to assert the validity and authenticity of the webhook and its payload.
On the receiving end, compute the same HMAC over the raw request body, before parsing it, and compare it with the `x-checkly-signature` header to assert the validity and authenticity of the webhook and its payload. Parsing and re-serializing the body can change its bytes and break the comparison.

Have a look at the code examples below on how to use the header and your favourite web framework.

<CodeGroup>

```javascript Node.js
// We store the webhook secret in an environment variable called CHECKLY_WEBHOOK_SECRET
const app = require('express')();
const bodyParser = require('body-parser');
const express = require('express');
const crypto = require('crypto');
const app = express();

function isVerifiedPayload (payload, signature) {
const secret = process.env.CHECKLY_WEBHOOK_SECRET
Expand All @@ -196,10 +198,11 @@ function isVerifiedPayload (payload, signature) {
return crypto.timingSafeEqual(Buffer.from(digest), Buffer.from(signature))
}

app.post('/webhook', bodyParser.json({ type: 'application/json' }), (request, response) => {
// express.raw() keeps the body as the bytes Checkly sent; parse it only after the signature is verified
app.post('/webhook', express.raw({ type: '*/*' }), (request, response) => {

const signature = request.headers['x-checkly-signature'];
const payload = JSON.stringify(request.body)
const payload = request.body

if (isVerifiedPayload(payload, signature)) {
console.log('Signature is valid')
Expand Down
Loading