When a service like Stripe or GitHub sends you a webhook, it signs the request so you can prove the request really came from them and was not altered in transit. Verifying that signature is the difference between trusting a webhook and accepting anything anyone posts to your endpoint.
Your webhook URL is public - anything that knows it can POST to it. Without verification you have no way to tell a real event from a forged one.
Skip verification and an attacker can POST a forged {"type":"payment_intent.succeeded"} straight to your handler and trigger whatever that event does - ship the product, credit the account, unlock the feature. A forged body cannot carry a signature that matches your secret, so verification rejects it.
The sender computes an HMAC - a hash of the request body keyed with a shared signing secret only you and the sender know - and puts it in a header. Your side recomputes the same HMAC with the same secret over the exact raw body and compares. Match means authentic and untampered; mismatch means a wrong secret, an altered body, or a forgery.
Stripe-Signature: t=<timestamp>,v1=<hmac>. HMAC-SHA256 of "{timestamp}.{body}", hex.X-Hub-Signature-256: sha256=<hmac>. HMAC-SHA256 of the body, hex.X-Shopify-Hmac-Sha256. HMAC-SHA256 of the body, base64.X-Slack-Signature: v0=<hmac>. HMAC-SHA256 of "v0:{timestamp}:{body}", hex.The signature is computed over the raw bytes of the body. Re-serializing or pretty-printing the JSON changes the bytes and breaks the check - the single most common reason verification fails in your own code.
Your secret stays in your browser. PeekHook computes the HMAC locally with the Web Crypto API - the signing secret is never sent to PeekHook, stored, or logged.