Skip to content

feat:533 webhook secrets#6227

Merged
jchui-wd merged 3 commits into
feat/344-ambient-agents-webhooksfrom
feat/533-webhook-secrets
Apr 24, 2026
Merged

feat:533 webhook secrets#6227
jchui-wd merged 3 commits into
feat/344-ambient-agents-webhooksfrom
feat/533-webhook-secrets

Conversation

@jchui-wd

@jchui-wd jchui-wd commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Adds opt-in secret-based authentication for webhook-triggered agentflows.
Is Tied to #6217

Changes

Backend

  • New webhookSecret (hidden) and webhookSecretConfigured (boolean) columns on ChatFlow, with migrations for all 4 databases
  • POST /chatflows/:id/webhook-secret and DELETE /chatflows/:id/webhook-secret to generate/remove secrets
  • Signature verification runs before all other validation — supports HMAC-SHA256/SHA1 (GitHub, Stripe, Slack) and plain token (GitLab)

Start Node (v1.2)

  • When webhookTrigger is selected, now shows a generate secrets section with signature header, and signature type.

UI

  • webhookURL field renders the full trigger URL with a copy button
  • webhookSecret field manages generate/regenerate/remove with the plaintext shown only immediately after generation, then masked on reload
Test Videos Demo

WrongSignatureType-Fail.mp4

WrongSignatureType-Fail.mp4

PlainToken-WrongHeaderName-Fail.mp4

PlainToken-WrongHeaderName-Fail.mp4

PlainToken-working.mp4

PlainToken-working.mp4

No-Secret-401.mp4

No-Secret-401.mp4

HMAC-non256-working.mp4

HMAC-non256-working.mp4

HMAC-256-working.mp4

HMAC-256-working.mp4

Screenshots

Screenshot 2026-04-16 at 12 13 14 PM

Signature Type
Screenshot 2026-04-16 at 12 13 32 PM

No Secrets Generated
Screenshot 2026-04-16 at 12 13 23 PM

Tests
Screenshot 2026-04-16 at 12 24 22 PM

@jchui-wd jchui-wd changed the base branch from feat/344-ambient-agents-webhooks to feat/389-Headers-Query-Params-Methods-Validation-Etc April 16, 2026 01:12

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request enhances the webhook trigger functionality in Agentflows by adding support for HTTP method selection, Content-Type validation, and secure signature verification (HMAC-SHA256 and Plain Token). It introduces new configuration fields in the Start node, updates the database schema to store webhook secrets, and implements comprehensive validation logic in the backend. Additionally, the UI is updated to allow users to manage webhook secrets and access namespaced variables for headers, query parameters, and body content. Review feedback suggests refining the raw body storage type and improving type validation for form-encoded webhook payloads.

I am having trouble creating individual review comments. Click here to see my feedback.

packages/server/src/index.ts (168)

medium

The buf provided by the verify callback of express.json and express.urlencoded is a Buffer. Casting it to a string using as unknown as string is misleading and potentially problematic if other parts of the application expect a string. Since verifyWebhookSignature correctly expects a Buffer, it is better to store it as such.

            ;(req as any).rawBody = buf

packages/server/src/services/webhook/index.ts (87-89)

medium

The strict typeof check will fail for number and boolean types when the incoming request is application/x-www-form-urlencoded, as all values in the request body are parsed as strings by default. Consider adding logic to handle numeric strings and boolean strings (e.g., "true", "false") to improve compatibility with various webhook senders.

        const typeMismatch = webhookBodyParams
            .filter((p) => {
                if (p.type == null || body?.[p.name] == null) return false
                const val = body[p.name]
                if (p.type === 'number') return isNaN(Number(val))
                if (p.type === 'boolean') return typeof val !== 'boolean' && val !== 'true' && val !== 'false'
                return typeof val !== p.type
            })
            .map((p) => p.name)

@jchui-wd jchui-wd marked this pull request as ready for review April 16, 2026 19:27
@jchui-wd jchui-wd changed the base branch from feat/389-Headers-Query-Params-Methods-Validation-Etc to feat/344-ambient-agents-webhooks April 17, 2026 21:11
@jchui-wd jchui-wd changed the base branch from feat/344-ambient-agents-webhooks to feat/389-Headers-Query-Params-Methods-Validation-Etc April 17, 2026 21:25
@jchui-wd jchui-wd changed the base branch from feat/389-Headers-Query-Params-Methods-Validation-Etc to feat/344-ambient-agents-webhooks April 17, 2026 21:25
…gger

Adds server-side webhook secret management (generate/clear/verify) and a
UI control in the Start node for configuring the secret, signature header,
and signature type (HMAC-SHA256 or plain token). Raw request body is now
captured before JSON parsing so HMAC signatures can be verified against the
original bytes. Migrations added for all four supported databases.
…validation

application/x-www-form-urlencoded payloads deliver all values as strings,
so the strict typeof check was incorrectly rejecting valid numeric ("42")
and boolean ("true"/"false") values. Updated the filter to coerce and
validate instead, with tests covering both JSON and form-encoded cases.
@jchui-wd jchui-wd force-pushed the feat/533-webhook-secrets branch from 6b46af4 to e1affad Compare April 17, 2026 21:38
@Column({ nullable: true, type: 'text' })
mcpServerConfig?: string

@Column({ nullable: true, type: 'text', select: false })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do u think if we group these into a column like webhookConfig, similar to mcpServerConfig

@jchui-wd jchui-wd Apr 21, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HenryHengZJ

I can group webhookSecret and webhookSecretConfigured make it as a webhookConfig just like mcpServerConfig, but I separated them intentionally because I didn't want the webhookSecret to be exposed when a user does a api/chatflow call since the secret is stored 'as is'.

so I added select: false for webhookSecrets, but we still need to know if it is configured so the Start.node can render out the correct UI if there is already a secret hence webhookSecretConfigured.

Any thoughts on this?

I think I should also add webhookSecret and webhookSecretConfigured in stripProtectedFields.ts, but I'll hold off until we are aligned on this.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i see it make sense, lets stick to this approach

@jchui-wd jchui-wd changed the title feat/533 webhook secrets feat:533 webhook secrets Apr 22, 2026
…te/update

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jchui-wd jchui-wd merged commit f8cf2ee into feat/344-ambient-agents-webhooks Apr 24, 2026
1 check passed
HenryHengZJ added a commit that referenced this pull request May 6, 2026
* feat(ambient-agents): Add webhook trigger UI on start node (#6068)

* feat(ambient-agents): Add webhook trigger UI on start node, handles in both canvas, agentflow is out of scope but shows temporary ui

* fix: resolve webhookURL copy button not appearing after first save

useParams() does not update when window.history.replaceState() is used
on first save (bypasses React Router). Fall back to Redux canvas.chatflow.id
so NodeInputHandler re-renders reactively when SET_CHATFLOW is dispatched.

* feat/365-366-Webhooks-Server-Route-And-Execution (#6164)

* feat(webhooks): add server route and validation for webhook trigger

- POST /api/v1/webhook/:id route (accepts all HTTP methods via router.all)
- Validates chatflow exists and is configured as webhookTrigger, returns 404 otherwise
- Wraps raw webhook payload as incomingInput.webhook for buildAgentflow

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(agentflow): wire up webhook flow execution (FLOWISE-366)

- Resolve {{ $webhook.field }} template variables in agentflow nodes
- Add required body param validation in webhook service
- Whitelist /api/v1/webhook/ to bypass global auth middleware
- Set $input to JSON payload in custom function nodes for webhook flows
- Add $webhook. autocomplete suggestions in node editors
- Unit tests for body param validation and pre-mutation body pass-through

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(webhooks): namespace webhook payload under $webhook.body.*

- Wrap webhook body as { webhook: { body } } in controller so $webhook.body.*,
  $webhook.headers.*, and $webhook.query.* can coexist as distinct namespaces
- Update suggestion option IDs/labels in UI from $webhook.* to $webhook.body.*
- Restrict webhookTrigger start option to agentflowv2 client only
- Remove static webhookURL placeholder from NodeInputHandler (agentflow)

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat/389-Webhooks-Headers-Query-params-Methods-validation (#6217)

* feat(ambient-agents): Add webhook trigger UI on start node, handles in both canvas, agentflow is out of scope but shows temporary ui

* fix: resolve webhookURL copy button not appearing after first save

useParams() does not update when window.history.replaceState() is used
on first save (bypasses React Router). Fall back to Redux canvas.chatflow.id
so NodeInputHandler re-renders reactively when SET_CHATFLOW is dispatched.

* feat(webhooks): add headers, query params & body validation to webhook trigger

- Add webhookTrigger input type to Start node with HTTP method, content
  type, and expected headers/query/body param configuration
- New /api/v1/webhook/:id route with method, content-type, header, body,
  and query param validation (400/405/415 on mismatch)
- Namespace webhook payload as $webhook.body.*, $webhook.headers.*,
  $webhook.query.* in the flow runtime
- Resolve $webhook.* variables in downstream nodes via buildAgentflow.ts
- Auto-unwrap form-encoded `payload` JSON strings (e.g. GitHub webhooks)
  so $webhook.body.* paths work regardless of content type
- Expose webhook variable suggestions in the node variable picker
- Show copyable webhook URL in the Start node canvas UI

* fixed a bug where downstream nodes cant reference values via node id, and a lowercase headers issue

* feat:533 webhook secrets (#6227)

* feat: add webhook secret & HMAC signature verification to webhook trigger

Adds server-side webhook secret management (generate/clear/verify) and a
UI control in the Start node for configuring the secret, signature header,
and signature type (HMAC-SHA256 or plain token). Raw request body is now
captured before JSON parsing so HMAC signatures can be verified against the
original bytes. Migrations added for all four supported databases.

* fix: accept string-coerced numbers and booleans in webhook body type validation

application/x-www-form-urlencoded payloads deliver all values as strings,
so the strict typeof check was incorrectly rejecting valid numeric ("42")
and boolean ("true"/"false") values. Updated the filter to coerce and
validate instead, with tests covering both JSON and form-encoded cases.

* fix: prevent mass-assignment of webhookSecret fields in chatflow create/update

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat:367 | Webhooks - Human Input + Callback Support (#6263)

* Added HITL support for webhooks

* feat: add async callback URL to webhook trigger
Optional Callback URL / Secret on the Start node (or x-callback-url
header). Webhook now returns 202 immediately and POSTs SUCCESS,
STOPPED (HITL), or ERROR to the callback URL, signed with HMAC-SHA256
when a secret is set. Retries 3x with 0s/3s/6s backoff.

* used getErrorMessage for error messages

* feat: add object/array body param types and per-option show/hide on d… (#6273)

* feat: add webhook secret & HMAC signature verification to webhook trigger

Adds server-side webhook secret management (generate/clear/verify) and a
UI control in the Start node for configuring the secret, signature header,
and signature type (HMAC-SHA256 or plain token). Raw request body is now
captured before JSON parsing so HMAC signatures can be verified against the
original bytes. Migrations added for all four supported databases.

* fix: accept string-coerced numbers and booleans in webhook body type validation

application/x-www-form-urlencoded payloads deliver all values as strings,
so the strict typeof check was incorrectly rejecting valid numeric ("42")
and boolean ("true"/"false") values. Updated the filter to coerce and
validate instead, with tests covering both JSON and form-encoded cases.

* Added HITL support for webhooks

* feat: add async callback URL to webhook trigger
Optional Callback URL / Secret on the Start node (or x-callback-url
header). Webhook now returns 202 immediately and POSTs SUCCESS,
STOPPED (HITL), or ERROR to the callback URL, signed with HMAC-SHA256
when a secret is set. Retries 3x with 0s/3s/6s backoff.

* feat: add object/array body param types and per-option show/hide on dropdowns

- Add object, array[string/number/boolean/object] as webhook body param types, available when content type is application/json
- Extend options fields with show/hide conditions so individual dropdown choices can be hidden based on other param values

* fix: prevent SSRF in webhook callback URL

Remove the x-callback-url header override that allowed any external
caller to control where the server sends POST requests. Callback URL
now only comes from the Start node config (authenticated users).

Add checkDenyList validation to block callback URLs targeting private
networks, cloud metadata endpoints, and loopback addresses.

* fix: exclude HTTP method from webhook URL copy

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: enhance webhook functionality in Start node

- Added new input options for webhook handling, including input modes (Custom Text, No Input, Full Webhook Payload) and response modes (Synchronous, Asynchronous, Streaming).
- Implemented request signature verification and callback URL handling for asynchronous responses.
- Updated validation logic for webhook requests, including content type and required headers.
- Enhanced tests to cover new webhook features and validation scenarios

* adds a generic SSE observer primitive and a webhook listener registry that lets the canvas watch incoming webhook executions live

* fix webhook tests by mocking webhook listener registry and updating expectations for chatId in createWebhook function

* fix: harden webhook trigger surface against SSRF, secret leakage, and listener data exposure

* fix: improve webhook listener reliability with initial heartbeat and logging

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Henry <hzj94@hotmail.com>
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.

3 participants