Skip to content

Create Slack integration with link unfurls - #2058

Merged
richiemcilroy merged 29 commits into
mainfrom
slack-integration
Jul 31, 2026
Merged

Create Slack integration with link unfurls#2058
richiemcilroy merged 29 commits into
mainfrom
slack-integration

Conversation

@richiemcilroy

@richiemcilroy richiemcilroy commented Jul 30, 2026

Copy link
Copy Markdown
Member

Connect Slack workspaces from org settings so Cap share links unfurl in Slack. Adds OAuth install/callback, events webhook, oEmbed + Player.js embed support, and a provider-agnostic integration_installations store.

Greptile Summary

Adds Slack workspace integration and link unfurl support.

  • Adds authenticated OAuth installation and callback routes with tenant-safe installation persistence.
  • Queues verified Slack events into a durable workflow before acknowledging them.
  • Adds public video metadata, oEmbed, and Player.js-compatible embed support.
  • Adds the provider-agnostic integration installation schema, migration, settings UI, and unit coverage.

Confidence Score: 4/5

The OAuth ownership-rejection path must be fixed before merging because it can leave an existing workspace installation with unusable credentials.

The callback exchanges the Slack OAuth code before installation persistence checks tenant ownership; when that check rejects a cross-organization installation, the replacement token is discarded and later unfurls continue using the stale stored token.

Files Needing Attention: apps/web/app/api/integrations/slack/callback/route.ts and apps/web/lib/integrations/installations.ts

Important Files Changed

Filename Overview
apps/web/lib/integrations/installations.ts Persists encrypted provider credentials and rejects cross-organization ownership changes, but that rejection occurs after Slack has issued replacement credentials.
apps/web/app/api/integrations/slack/callback/route.ts Exchanges Slack OAuth credentials before validating whether the workspace installation belongs to another organization, leaving the existing installation with stale credentials on rejection.
apps/web/app/api/integrations/slack/events/route.ts Verifies Slack signatures over the raw body and durably queues supported events before acknowledging them.
apps/web/workflows/slack-event.ts Processes queued Slack events with step retries and delayed recovery for transient failures.
apps/web/lib/slack/unfurl.ts Parses Slack events, resolves eligible public recordings, and builds Slack video unfurls.
packages/database/schema.ts Adds the provider-agnostic integration installations table with tenant ownership and encrypted credential storage.
Prompt To Fix All With AI
### Issue 1
apps/web/app/api/integrations/slack/callback/route.ts:70-83
**Ownership rejection leaves stale token**

When a workspace already connected to one organization completes OAuth from another organization, this callback exchanges the code before the repository rejects the ownership change. Slack replaces the workspace credentials, but the newly issued token is discarded while the original organization retains the previous token, causing subsequent link unfurls to fail authentication.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (3): Last reviewed commit: "fix: recover exhausted Slack event retri..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

@cursor

cursor Bot commented Jul 30, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Comment thread apps/web/lib/slack/oauth-state.ts Dismissed
Comment thread apps/web/lib/integrations/installations.ts Outdated
Comment thread apps/web/app/api/integrations/slack/events/route.ts Outdated
Comment thread apps/web/lib/slack/unfurl.ts Outdated
Comment thread apps/web/app/embed/[videoId]/_components/use-player-js-receiver.ts Outdated
@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

@richiemcilroy

Copy link
Copy Markdown
Member Author

hey @greptileai, please re-review the PR

Comment thread apps/web/app/api/integrations/slack/callback/route.ts
Comment thread apps/web/workflows/slack-event.ts Outdated
state.organizationId,
);
await requireOrganizationSettingsManager(user.id, organizationId);
const result = await exchangeSlackOAuthCode({

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Slack OAuth callback exchanges token before validating cross-tenant ownership

OAuth token exchange happens before cross-tenant ownership check, leaving stale credentials on rejection.

Revoke the newly issued Slack token when cross-org ownership is rejected, or check ownership after exchange and before persistence.

AI prompt
Check if this security scanner issue is valid. If so, understand the root cause and fix it. If appropriate, update or add tests. Keep the change focused and preserve intended behavior.

<file name="apps/web/app/api/integrations/slack/callback/route.ts">
<violation number="1" location="apps/web/app/api/integrations/slack/callback/route.ts:70">
<priority>P2</priority>
<title>Slack OAuth callback exchanges token before validating cross-tenant ownership</title>
<evidence>The callback exchanges the Slack OAuth code before saveSlackInstallation checks whether the workspace is already owned by another organization. Slack invalidates the previous token when issuing a new one, so a rejected cross-org installation leaves the original organization with a stale token.</evidence>
<recommendation>After exchanging the OAuth code, if saveIntegrationInstallation rejects the installation because the workspace is already owned by another organization, revoke the newly issued Slack token via auth.revoke before returning an error. Alternatively, refactor the flow to validate ownership after fetching the team identity but before persisting credentials.</recommendation>
</violation>
</file>

@richiemcilroy
richiemcilroy merged commit 4a35694 into main Jul 31, 2026
19 of 22 checks passed
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.

2 participants