Skip to content

feat(triggers): add Zoom webhook triggers#3992

Merged
waleedlatif1 merged 10 commits intostagingfrom
waleedlatif1/add-zoom-trigger
Apr 6, 2026
Merged

feat(triggers): add Zoom webhook triggers#3992
waleedlatif1 merged 10 commits intostagingfrom
waleedlatif1/add-zoom-trigger

Conversation

@waleedlatif1
Copy link
Copy Markdown
Collaborator

Summary

  • Add 6 Zoom webhook triggers: meeting started/ended, participant joined/left, recording completed, and generic webhook
  • Implement Zoom provider handler with endpoint.url_validation challenge-response protocol and x-zm-signature HMAC-SHA256 signature verification
  • Add event-type filtering so each trigger only fires on its matching Zoom event

Type of Change

  • New feature

Testing

Tested manually

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Apr 6, 2026 7:42pm

Request Review

@cursor
Copy link
Copy Markdown

cursor bot commented Apr 6, 2026

PR Summary

Medium Risk
Introduces new webhook ingestion/auth logic (HMAC verification, URL-validation challenge) and new trigger routing, which could affect webhook acceptance/rejection and event firing behavior. Changes are additive but touch security-sensitive request verification paths.

Overview
Adds Zoom webhook support end-to-end: a new zoom provider handler with endpoint.url_validation challenge responses and x-zm-signature HMAC-SHA256 verification, and registers it for challenge handling and provider dispatch.

Introduces 6 new Zoom triggers (meeting started/ended, participant joined/left, recording completed, and zoom_webhook for all events) with event-type filtering via isZoomEventMatch, plus updates integrations.json to expose these triggers (and expands HubSpot trigger catalog + adds Salesforce triggers) with updated triggerCount values.

Reviewed by Cursor Bugbot for commit 3813931. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 6, 2026

Greptile Summary

This PR adds 6 Zoom webhook triggers (meeting started/ended, participant joined/left, recording completed, and a generic catch-all) with a complete security implementation including challenge-response validation and HMAC-SHA256 signature verification.

  • Implements endpoint.url_validation challenge-response protocol with mandatory HMAC-SHA256 signature verification on the challenge itself, closing the previously identified chosen-plaintext HMAC oracle attack vector
  • Validates x-zm-signature with a 300-second replay window aligned with Zoom's official reference implementation (zoom/webhook-sample)
  • Authentication fails closed: missing secretToken in providerConfig returns 401 immediately
  • Event-type filtering via isZoomEventMatch with ZOOM_TRIGGER_EVENT_MAP; unknown trigger IDs fail closed (all events filtered out)
  • All 6 triggers follow the established codebase pattern — buildTriggerSubBlocks, per-event output builders, dynamic import of isZoomEventMatch in matchEvent consistent with jira.ts, github.ts, intercom.ts, and others
  • Integrations landing page updated with correct id fields for all 6 triggers

Confidence Score: 5/5

This PR is safe to merge — all prior security concerns have been resolved and the implementation follows established patterns

All previously identified P0/P1 issues (HMAC oracle attack, replay attack window, fail-open authentication, missing mandatory challenge signature check) have been addressed per prior review threads. The dynamic import pattern in matchEvent is consistent with the established codebase convention across jira.ts, github.ts, intercom.ts, and others. No new P0 or P1 findings identified.

No files require special attention

Important Files Changed

Filename Overview
apps/sim/lib/webhooks/providers/zoom.ts Core Zoom webhook provider: HMAC-SHA256 with 300s replay window, fail-closed auth, mandatory challenge signature verification — all prior security concerns resolved
apps/sim/triggers/zoom/utils.ts Shared utilities: event-map with fail-closed unknown-ID handling, well-typed output builders for all 4 event categories
apps/sim/triggers/zoom/meeting_started.ts Meeting Started trigger with includeDropdown:true (primary trigger for type selector dropdown)
apps/sim/triggers/zoom/meeting_ended.ts Meeting Ended trigger, consistent with established codebase pattern
apps/sim/triggers/zoom/participant_joined.ts Participant Joined trigger, consistent with established codebase pattern
apps/sim/triggers/zoom/participant_left.ts Participant Left trigger, consistent with established codebase pattern
apps/sim/triggers/zoom/recording_completed.ts Recording Completed trigger, consistent with established codebase pattern
apps/sim/triggers/zoom/webhook.ts Generic webhook trigger accepting all Zoom events, consistent with established codebase pattern
apps/sim/triggers/zoom/index.ts Barrel export for all 6 Zoom triggers
apps/sim/triggers/registry.ts All 6 Zoom triggers registered with correct key names matching their trigger IDs
apps/sim/lib/webhooks/providers/registry.ts Zoom provider handler registered alongside all other providers
apps/sim/app/(landing)/integrations/data/integrations.json Zoom integration listing updated with all 6 trigger entries including correct id fields

Sequence Diagram

sequenceDiagram
    participant Z as Zoom
    participant R as Webhook Route
    participant ZH as zoomHandler
    participant DB as Database
    participant Q as Job Queue

    Z->>R: POST /api/webhooks/trigger/{path}
    R->>R: parseWebhookBody() → {body, rawBody}
    R->>ZH: handleChallenge(body, request, requestId, path)
    alt event = endpoint.url_validation
        ZH->>ZH: check x-zm-signature + x-zm-request-timestamp
        note over ZH: Reject if headers missing
        ZH->>DB: SELECT webhook WHERE path AND provider='zoom'
        DB-->>ZH: webhook record with secretToken
        ZH->>ZH: validateZoomSignature(secretToken, sig, ts, JSON.stringify(body))
        alt signature valid
            ZH-->>R: NextResponse({plainToken, encryptedToken})
            R-->>Z: 200 + challenge response
        else invalid / no secret
            ZH-->>R: null
            R-->>Z: 401
        end
    else not a challenge
        ZH-->>R: null
    end
    R->>R: findAllWebhooksForPath(path)
    loop for each matching webhook
        R->>ZH: verifyAuth({request, rawBody, providerConfig})
        alt secretToken missing
            ZH-->>R: 401 Unauthorized
        else sig/ts headers missing
            ZH-->>R: 401 Unauthorized
        else HMAC mismatch OR timestamp delta > 300s
            ZH-->>R: 401 Unauthorized
        else all checks pass
            ZH-->>R: null (continue)
        end
        R->>ZH: matchEvent({body, providerConfig})
        ZH->>ZH: isZoomEventMatch(triggerId, body.event)
        alt event matches trigger ID
            ZH-->>R: true
            R->>Q: enqueueWebhookExecution()
            R-->>Z: 200 OK
        else no match
            ZH-->>R: false
            R->>R: skip workflow
        end
    end
Loading

Reviews (8): Last reviewed commit: "fix(triggers): increase Zoom timestamp t..." | Re-trigger Greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

… signature verification

Add 6 Zoom webhook triggers (meeting started/ended, participant joined/left, recording completed, generic webhook) with full Zoom protocol support including endpoint.url_validation challenge-response handling and x-zm-signature HMAC-SHA256 verification.
- Add 30s timestamp freshness check to prevent replay attacks
- Return null from handleChallenge when no secret token found instead of responding with empty-key HMAC
- Remove all `as any` casts from output builder functions
- verifyAuth now fails closed (401) when secretToken is missing
- handleChallenge DB query filters by provider='zoom' to avoid cross-provider leaks
- handleChallenge verifies x-zm-signature before responding to prevent HMAC oracle
@waleedlatif1 waleedlatif1 force-pushed the waleedlatif1/add-zoom-trigger branch from 291f79c to bd0a5aa Compare April 6, 2026 18:52
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 291f79c. Configure here.

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

…ding page data

- isZoomEventMatch now returns false for unrecognized trigger IDs
- Update integrations.json with 6 Zoom triggers
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 3813931. Configure here.

@waleedlatif1 waleedlatif1 merged commit 18a7868 into staging Apr 6, 2026
12 checks passed
@waleedlatif1 waleedlatif1 deleted the waleedlatif1/add-zoom-trigger branch April 6, 2026 20:39
emir-karabeg pushed a commit that referenced this pull request Apr 7, 2026
* feat(triggers): add Zoom webhook triggers with challenge-response and signature verification

Add 6 Zoom webhook triggers (meeting started/ended, participant joined/left, recording completed, generic webhook) with full Zoom protocol support including endpoint.url_validation challenge-response handling and x-zm-signature HMAC-SHA256 verification.

* fix(triggers): use webhook.isActive instead of non-existent deletedAt column

* fix(triggers): address PR review feedback for Zoom webhooks

- Add 30s timestamp freshness check to prevent replay attacks
- Return null from handleChallenge when no secret token found instead of responding with empty-key HMAC
- Remove all `as any` casts from output builder functions

* lint

* fix(triggers): harden Zoom webhook security per PR review

- verifyAuth now fails closed (401) when secretToken is missing
- handleChallenge DB query filters by provider='zoom' to avoid cross-provider leaks
- handleChallenge verifies x-zm-signature before responding to prevent HMAC oracle

* fix(triggers): rename type to meeting_type to avoid TriggerOutput type collision

* fix(triggers): make challenge signature verification mandatory, not optional

* fix(triggers): fail closed on unknown trigger IDs and update Zoom landing page data

- isZoomEventMatch now returns false for unrecognized trigger IDs
- Update integrations.json with 6 Zoom triggers

* fix(triggers): add missing id fields to Zoom trigger entries in integrations.json

* fix(triggers): increase Zoom timestamp tolerance to 300s per Zoom docs
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.

1 participant