Testing webhooks locally without public URL

Need to test webhook payloads on localhost. Currently using ngrok but connection drops after 2 hours on free tier. Looking for alternatives that don't require public deployment.

Specifically:

  • Need stable tunnel for multi-day testing
  • Must inspect raw POST body for signature verification
  • Running Node.js handler locally

What are people using? Cloudflare Tunnel? LocalStack? Something else?

Parents
  • From a security perspective, i.e., credential exposure in tunnel URLs — Cloudflare Tunnel uses authenticated connections to their edge, but the local cloudflared process runs with whatever permissions you give it. Worth running in a container or with minimal privileges, especially if you're tunneling to a handler that logs request bodies (which may contain PII under GDPR/CCPA).

    Also worth noting: the FieldPulse webhook signature uses HMAC-SHA256 with a shared secret. The signature verification is vulnerable to timing attacks if implemented with naive string comparison. Use crypto.timingSafeEqual in Node.js:

    const crypto = require('crypto');
    const expected = Buffer.from(signature, 'hex');
    const actual = crypto.createHmac('sha256', secret).update(rawBody).digest();
    if (!crypto.timingSafeEqual(expected, actual)) {
      throw new Error('Invalid signature');
    }

    Edge case: if the payload exceeds Node's default memory limits (e.g., large photo attachments in webhook extensions), the raw body buffering above will crash the process. Consider streaming verification for production use.

Reply
  • From a security perspective, i.e., credential exposure in tunnel URLs — Cloudflare Tunnel uses authenticated connections to their edge, but the local cloudflared process runs with whatever permissions you give it. Worth running in a container or with minimal privileges, especially if you're tunneling to a handler that logs request bodies (which may contain PII under GDPR/CCPA).

    Also worth noting: the FieldPulse webhook signature uses HMAC-SHA256 with a shared secret. The signature verification is vulnerable to timing attacks if implemented with naive string comparison. Use crypto.timingSafeEqual in Node.js:

    const crypto = require('crypto');
    const expected = Buffer.from(signature, 'hex');
    const actual = crypto.createHmac('sha256', secret).update(rawBody).digest();
    if (!crypto.timingSafeEqual(expected, actual)) {
      throw new Error('Invalid signature');
    }

    Edge case: if the payload exceeds Node's default memory limits (e.g., large photo attachments in webhook extensions), the raw body buffering above will crash the process. Consider streaming verification for production use.

Children
No Data