Skip to content

Webhook Verification

Check that webhooks really came from GitHub, Stripe, Shopify, Slack, or any provider that signs requests. Forged deliveries never reach your machine.

Summary

A signed webhook carries proof of who sent it. Choose your provider, paste the signing secret from its dashboard, and Localport checks that proof on every delivery before routing it. Genuine events reach your code, and forged, tampered or replayed ones stop at the tunnel.

How signature verification works#

A provider that sends webhooks signs each delivery with a secret it shares with you. The signature is an HMAC-SHA256 over the request body, carried in a header. Localport recomputes it with the same secret and compares the two, and a delivery that does not match is refused before it is routed to your machine.

A webhook URL is public, since the provider has to be able to reach it. Anyone who learns the address can post to it, and a valid signature distinguishes the provider's deliveries from everything else.

Running that check at the tunnel keeps forged deliveries off your machine, and your local handler needs no verification code while you develop against it. The check covers HTTP and HTTPS traffic, on a tunnel and on a fleet.

Enable signature verification#

Signature Verification: choose the provider, then paste its signing secret.

1. Open the tunnel's Settings and find HTTP Protection.

2. Turn on Signature Verification.

3. Choose your Provider.

4. Paste the Signing secret from the provider's dashboard.

5. Click Save.

Choosing Custom adds a Signature header field for the header name your sender uses. The four named providers have a header fixed by the vendor, so there is nothing to enter.

Saving is refused with verification on and no secret, and with Custom selected and no header name. Editing the setting requires the Admin role. The secret is encrypted at rest and masked in the dashboard once saved.

Supported providers#

ProviderHeaderSigned material
GitHubX-Hub-Signature-256The body, hex encoded
StripeStripe-SignatureThe timestamp and the body
ShopifyX-Shopify-Hmac-Sha256The body, base64 encoded
SlackX-Slack-SignatureA version marker, the timestamp and the body
CustomThe header you nameThe body, hex or base64

Every scheme is HMAC-SHA256 with your secret. They differ in what goes into the hash and how the result is encoded, so the provider you choose selects the scheme, not just a label.

Replay protection#

Stripe and Slack sign a timestamp alongside the body, and Localport checks it against a five minute window in each direction. A delivery captured today cannot be replayed next week, even carrying a signature that is still valid.

GitHub and Shopify sign the body alone, so there is no timestamp to check. A Custom sender is treated the same way.

Rejected deliveries#

A delivery whose signature does not match is answered with 403 Forbidden and never reaches your machine. The response carries no detail, so a sender that cannot produce a valid signature learns only that it was refused. Providers record that as a failed delivery and apply their usual retry schedule.

Verification reads the request body, which is capped at 1 MB per delivery. A larger body is answered with 413 and is never forwarded unchecked.

Changing the provider or secret#

Pick the new provider or paste the new secret and save. The change applies immediately, with no restart and no reconnection. Every delivery is checked, so the next one arriving is measured against the new settings.

What Localport reads#

The signature is checked against the request exactly as the provider sent it. The payload is not read, parsed, logged or stored, and nothing in it takes part in the decision.

Your service receives the request unchanged.

Limitations#

  • Verification applies to HTTP and HTTPS. A TCP or TLS tunnel carries no request to check, so restrict it with an IP allowlist.
  • A tunnel holds one provider and one secret. An endpoint receiving deliveries from two providers needs a tunnel for each.
  • A body over 1 MB is refused, and is never forwarded unchecked.

Frequently asked questions#

How do I verify webhook signatures without writing code?

Turn on Signature Verification under HTTP Protection in your tunnel's settings, choose the provider, and paste the signing secret from their dashboard. Every delivery is checked before it is routed, so your local app receives genuine requests only.

Which webhook providers are supported?

GitHub, Stripe, Shopify and Slack have built-in schemes. Custom covers any sender that signs the request body with HMAC-SHA256 and puts the result in a header you name, in hex or base64.

Why do my webhooks fail after turning this on?

Usually the wrong secret, since providers issue a separate one per endpoint, or the wrong provider, since each hashes different material. On Stripe and Slack it can also be a drifted clock, because their signatures cover a timestamp checked against a five minute window.

Can I test this with curl?

Not with an ordinary curl request, which carries no signature and is refused. Use your provider's send-test-event or redeliver button, which produces a correctly signed delivery.

Does this protect against replay attacks?

On providers that sign a timestamp, yes. Stripe and Slack deliveries are checked against a five minute window, so a captured request cannot be replayed later even carrying a valid signature. GitHub and Shopify sign the body alone and have no timestamp to check.

What does the provider see when a delivery is rejected?

403 Forbidden, with no detail in the body. Their dashboard records a failed delivery and their normal retry schedule applies. Nothing reaches your machine.

Is there a size limit on a webhook body?

Yes. Verification reads up to 1 MB per delivery, and a larger body is answered with 413 and never forwarded unchecked. Webhook payloads sit far below that in normal use.

Is my signing secret stored safely?

It is encrypted at rest and masked in the dashboard once saved. It is used to compute the expected signature for each delivery and is sent nowhere.

Does signature verification work on a Fanout tunnel?

Yes, and it is the check that suits one. A Fanout tunnel delivers each request to every connected teammate, and verification runs once at the tunnel, so a forged delivery reaches none of them. Client certificates are not an option there, since a provider presents none.