Skip to content

Docs: add an "Operating & rotating webhook routes" guide (secret rotation, verifying signatures, debugging 401s) #88

Description

@Aaronontheweb

Summary

We recently stood up an inbound webhook route against a Stripe-style HMAC-timestamped provider and hit several things that are answerable from the source but not currently covered in a user-facing guide. Proposing a single "Operating & rotating webhook routes" guide so the next person doesn't have to read WebhookEndpointRouteBuilderExtensions / WebhookRequestVerifier to figure them out.

All content below is framework-general — no secrets or private data required to write it. Provider names (Stripe, and providers that sign Stripe-style like some email gateways) appear only as generic examples.

Proposed guide sections

1. Rotating a signing secret without recreating the route

  • netclaw webhooks set <route> --update-only --secret-file <path> updates just the secret; everything else on the route is preserved.
  • Route files hot-reload — no daemon restart needed.
  • Prefer --secret-file / --secret-env over --secret <value> so the secret never lands in shell history.
  • Note that the route JSON stores the secret; rotating means updating it in both the provider and the route.

2. Reading delivery outcomes (and what each status means)

Document the request pipeline order, because it makes debugging deterministic:

route lookup → body read → signature verificationevent allowlist → dedup / rate-limit → dispatch

  • 401 Unauthorized → signature verification failed (wrong key, wrong signed-payload construction, or stale timestamp). Verification runs before the event allowlist, so a bad signature never reaches filtering.
  • 202 with WebhookIgnoredResponse (reason: event_filtered) → the signature passed; the event type just isn't in the route's --events allowlist.
  • 202 with WebhookAcceptedResponse → verified, allowed, dispatched (a session is created).

The practical tip worth calling out: because verification precedes filtering, a 202 event_filtered response is a perfect setup smoke-test — it confirms your secret/headers are correct before a real (allowlisted) event ever arrives. A provider's "send test" button (which usually sends a non-allowlisted event type) is enough to prove the signature path.

3. Configuring an HMAC-timestamped (Stripe-style) provider

  • --verification-kind hmac-timestamped, plus --signature-header, --event-header, --delivery-header.
  • Wiring --event-header is what makes the --events allowlist and delivery-ID dedup actually work.
  • Defaults that match Stripe-style providers and usually shouldn't be overridden: timestamp-field t, signature-field v1, signed-payload-separator ., signature-tolerance-seconds 300.
  • The signature is HMAC-SHA256 with key UTF8(secret) over "{t}.{rawBody}", emitted as lowercase hex — computed over the raw received body.

4. Debugging a persistent 401

  • Confirm what the provider actually signs with: the guide should stress verifying that the provider signs the raw body with the plaintext secret you were handed (not a hashed/derived/transformed key). A provider bug or a copy-paste of the wrong secret form is a common cause.
  • Where deliveries log, and how to distinguish a verification_failed from an event_filtered.
  • How to reveal/inspect the registered secret (netclaw webhooks show <route> --show-secret).

5. Webhook (and reminder) sessions run headless — pre-approve tools

  • Webhook- and reminder-triggered sessions are non-interactive, so any tool the handler prompt calls must be pre-approved (e.g. in tool-approvals.json) for the route's audience, or the call fails closed with no human to approve it.
  • Worth a cross-link from the reminders/scripting docs too, since it's the same failure mode.

Why

Each of these took a source read or trial-and-error to discover; none are hard once written down. A short guide (plus a couple of netclaw webhooks set --help cross-references) would cover the full lifecycle: register → verify → operate → rotate → debug.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions