Skip to content

feat: Webhook Trigger Router with HMAC Signature & Anti-Replay Protec… - #978

Merged
ayomideadeniran merged 2 commits into
SoroLabs:mainfrom
OG-wura:Webhook_Trigger
Aug 3, 2026
Merged

feat: Webhook Trigger Router with HMAC Signature & Anti-Replay Protec…#978
ayomideadeniran merged 2 commits into
SoroLabs:mainfrom
OG-wura:Webhook_Trigger

Conversation

@OG-wura

@OG-wura OG-wura commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Close #905

Webhook Trigger Router with HMAC Signature & Anti-Replay Protection

Summary

Exposes a secure POST /webhook/trigger endpoint that accepts HMAC SHA-256 signed requests to trigger task executions on-demand. Prevents replay attacks via timestamp sliding window and nonce deduplication, then dispatches directly to the execution queue — eliminating polling latency for real-world events.

Changes

keeper/src/config.js

  • Default inboundWebhooks.path changed to /webhook/trigger (overridable via INBOUND_WEBHOOK_PATH)

keeper/src/webhookTrigger.js

  • _resolvePath(req) — dynamically extracts the request path from the URL at runtime so the handler correctly verifies HMAC signatures for any registered path (canonical request includes the path)
  • verify() now uses the resolved path — both /webhook/trigger and legacy /webhooks/task-executions work transparently
  • reject() includes keyId / eventId in structured error responses

keeper/src/metrics.js

  • webhookPaths Set — supports multiple registered webhook paths
  • Constructor + setWebhookHandler() pre-register legacy /webhooks/task-executions alongside the configured path (zero-config backward compat)
  • registerWebhookPath() — extensibility for additional routes
  • Route check: this.webhookPaths.has(url.pathname) replaces url.pathname === this.webhookPath

keeper/__tests__/webhookTrigger.test.js (+138 lines)

  • Path resolution tests: default /webhook/trigger, legacy /webhooks/task-executions, URL parse failure fallback
  • Cross-cutting auth scenarios: missing headers, expired timestamp, unknown key ID, structured error with keyId

Security Properties

Property Mechanism File
HMAC SHA-256 crypto.createHmac('sha256') on canonical request webhookAuth.js:98
Timestamp window 5min tolerance via Math.abs(now - timestamp) webhookAuth.js:177
Nonce anti-replay InMemoryReplayStore with TTL eviction webhookAuth.js:101
Timing-safe comparison crypto.timingSafeEqual() webhookAuth.js:16
Event-level dedup EventId keyed replay store webhookTrigger.js:99
Body size limit 1MB max, early connection close webhookTrigger.js:5
Path-aware HMAC _resolvePath() from request URL webhookTrigger.js:44

Flow

Client                     Metrics Server              WebhookTriggerHandler          ExecutionQueue
  │                             │                             │                             │
  │  POST /webhook/trigger      │                             │                             │
  │  Headers: x-sorotask-signature, -timestamp, -nonce, -key-id │                             │
  │  Body: { type, eventId, taskId }                           │                             │
  │────────────────────────────►│                             │                             │
  │                             │  route match                │                             │
  │                             │────────────────────────────►│                             │
  │                             │                             │                             │
  │                             │                             │  verify(method, path,        │
  │                             │                             │    headers, rawBody)         │
  │                             │                             │  ├─ timestamp window         │
  │                             │                             │  ├─ nonce replay check       │
  │                             │                             │  ├─ HMAC SHA-256 match       │
  │                             │                             │  └─ eventId dedup            │
  │                             │                             │                             │
  │                             │                             │  enqueue(taskId, context)   │
  │                             │                             │────────────────────────────►│
  │                             │  202 { status, eventId,     │                             │
  │                             │        taskId }             │                             │
  │◄────────────────────────────│─────────────────────────────│                             │

@vercel

vercel Bot commented Jul 26, 2026

Copy link
Copy Markdown

@OG-wura is attempting to deploy a commit to the Ayomide Adeniran's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Jul 26, 2026

Copy link
Copy Markdown

@OG-wura Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@ayomideadeniran

Copy link
Copy Markdown
Contributor

pr under review, i will get back to you if i find any wrong implementations

@ayomideadeniran
ayomideadeniran merged commit e44636a into SoroLabs:main Aug 3, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🤖 [KEEPER] Webhook Trigger Router with HMAC Signature & Anti-Replay Protection

2 participants