Skip to main content

Verify webhook signature

The Verify webhook signature block checks that a request to a webhook event listener really comes from the service that signs it, and continues with its Valid or Invalid branch. Put it first in the flow and answer invalid requests with a Respond to webhook block and status 401. Some services, like ER:LC, only accept a webhook URL that does this.

Pick the service that sends the requests:

ServiceKey
ER:LCNone, ER:LC's public key is built in
GitHubThe secret of the webhook
StripeThe signing secret starting with whsec_
SlackThe app's signing secret
DiscordNone, your app's public key is used
Standard WebhooksThe signing secret starting with whsec_, or the public key starting with whpk_. Used by Svix, Clerk, Resend and others

With Discord, use it for webhook events, like your app being installed. Discord sends a ping when you save the URL in the Developer Portal, which the flow has to answer with status 204 after verifying it. Don't use the URL as the Interactions Endpoint URL, Kite already receives your app's interactions.

Store a secret key as a secret and enter it as {{secrets.NAME}}. Requests whose timestamp is more than 5 minutes off are invalid for the services that sign one, so a request that got out can't be sent again later.

For another service, pick Custom and set the algorithm (HMAC with SHA-256, SHA-1 or SHA-512, or Ed25519), what the service signs, the header with the signature and its encoding. For example, a service that signs a timestamp header and the body with HMAC SHA-256 needs the signed message {{webhook.headers['x-timestamp']}}.{{webhook.body}} and the signature {{webhook.headers['x-signature']}}. Remove a prefix like sha256= with {{ trimPrefix(webhook.headers['x-signature'], 'sha256=') }}.

Anything wrong with the request, like a missing header, makes it invalid. The block only fails when its settings are wrong, like a key that isn't one. It costs no credits.

Loading...