GitHub Webhooks

GitHub Webhooks, Verified & Reliable.

Validate X-Hub-Signature-256, add DLQ/replay, and stop losing events when deploys or timeouts happen.

Works with webhooks from

Stripe Shopify GitHub Twilio SendGrid

What GitHub actually does

GitHub signs webhook payloads with X-Hub-Signature-256 when a secret is configured. This header contains an HMAC-SHA256 hash prefixed with sha256=.

The older X-Hub-Signature header uses SHA-1, which is legacy. GitHub recommends using SHA-256 for all new webhook implementations.

Never miss a PR, push, or build event

CI/CD downtime and deploy windows shouldn't mean lost GitHub webhooks.

Signature Validation UI

Visual mismatch debugging for X-Hub-Signature-256 with clear reasons: algorithm, secret, or body differences.

  • SHA-256 validation
  • Prefix parsing (sha256=)
  • Constant-time comparison

DLQ & Replay

Failed PR/push/issue events stored with full audit trail. One-click replay to staging or prod.

  • No lost build triggers
  • Replay to staging safely
  • Complete event history

Latency & Retry Timeline

See exactly what happened, when. Response times, status codes, retry attempts—all visualized.

  • Per-attempt latency
  • Status code tracking
  • Error details captured

GitHub Quick-Start

Add EventDock to your GitHub webhooks in under 5 minutes

1

Create EventDock endpoint

Select GitHub as the provider and paste your upstream URL (CI/CD webhook handler, notification service, etc.).

2

Set webhook secret

Generate a strong secret in GitHub webhook settings. Paste the same secret into EventDock for signature verification.

3

Configure GitHub webhook

In your GitHub repo/org settings → Webhooks, add the EventDock URL. Select events (push, PR, issues, etc.).

4

Test & enable alerts

Trigger a webhook (push, open PR), view it in EventDock's Stream, and enable alerts for failed deliveries.

Test your GitHub signature with curl
curl -s https://api.eventdock.app/in/<endpoint-id> \
  -H "X-Hub-Signature-256: sha256=<hex-digest>" \
  -H "Content-Type: application/json" \
  --data '{"action":"opened","pull_request":{"id":123}}'

In EventDock, open Stream → verify signature verdict and replay to staging.

Signature verification examples

Validate X-Hub-Signature-256 correctly

Node.js verification

Parse the sha256= prefix and perform constant-time hex comparison. CRITICAL: Decode hex strings to bytes before comparison.

const crypto = require('crypto');

function verifyGitHubSignature(payload, signatureHeader, secret) {
  // Header format: "sha256="
  if (!signatureHeader || !signatureHeader.startsWith('sha256=')) {
    throw new Error('Invalid signature header format');
  }

  const sigHex = signatureHeader.slice(7); // Remove "sha256=" prefix

  // Compute expected signature
  const expectedHex = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');

  // CRITICAL: Decode hex strings to bytes for timing-safe comparison
  const a = Buffer.from(sigHex, 'hex');
  const b = Buffer.from(expectedHex, 'hex');
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

// Usage in Express
app.post('/github-webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-hub-signature-256'];
  const secret = process.env.GITHUB_WEBHOOK_SECRET;

  try {
    verifyGitHubSignature(req.body, signature, secret);
    // Process webhook...
    res.status(200).send('OK');
  } catch (err) {
    res.status(401).send('Unauthorized');
  }
});

Python verification

import hmac
import hashlib

def verify_github_signature(payload: bytes, signature_header: str, secret: str) -> bool:
    """Verify GitHub X-Hub-Signature-256."""
    # Parse header (format: "sha256=")
    if not signature_header or not signature_header.startswith('sha256='):
        raise ValueError('Invalid signature header')

    signature = signature_header[7:]  # Remove "sha256=" prefix

    # Compute expected signature
    expected = hmac.new(
        secret.encode('utf-8'),
        payload,
        hashlib.sha256
    ).hexdigest()

    # Constant-time comparison
    return hmac.compare_digest(expected, signature)

# Usage in Flask
@app.route('/github-webhook', methods=['POST'])
def github_webhook():
    signature = request.headers.get('X-Hub-Signature-256')
    secret = os.environ['GITHUB_WEBHOOK_SECRET']

    if not verify_github_signature(request.data, signature, secret):
        return 'Unauthorized', 401

    # Process webhook...
    return 'OK', 200

Frequently Asked Questions

Which GitHub webhook signature header should I use?

Prefer X-Hub-Signature-256 which uses SHA-256. The older X-Hub-Signature header uses SHA-1, which is legacy and less secure. GitHub recommends using SHA-256 for all new implementations.

Can I replay an old GitHub webhook payload to staging?

Yes. EventDock allows one-click replay of any GitHub webhook to production or staging endpoints with full audit trail, making it easy to test PR/push/issue event handling without triggering real GitHub actions.

Does EventDock modify GitHub webhook headers or User-Agent?

No. EventDock forwards original GitHub headers including User-Agent unchanged. We add X-EventDock-* metadata headers for tracing but preserve all original request headers and body.

How do I verify GitHub X-Hub-Signature-256?

Parse the sha256= prefix from the header, compute HMAC-SHA256 of the raw request body using your webhook secret, and perform a constant-time hex string comparison.

What happens if my CI/CD is down when a PR webhook arrives?

EventDock buffers the webhook and retries with exponential backoff until your CI/CD recovers. Failed events go to DLQ where you can replay them once your service is back online.

Can I see the exact latency and retry timeline for GitHub webhooks?

Yes. EventDock shows you exactly when each delivery attempt happened, the response time, status code, and any errors. This makes debugging GitHub webhook issues much faster.

Start free — never miss a GitHub event

5,000 events/month free. No credit card required. 5-minute setup.

Start Free Trial

Other providers: Stripe · Shopify