From 98fa2ee65779123f803a38b11202d4a7ea314c2e Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Thu, 23 Jul 2026 13:32:03 -0700 Subject: [PATCH] improvement(slack): request the approved mention/assistant/DM scopes, advertised on v2 only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Slack app review has since approved `app_mentions:read`, `assistant:write`, and `im:history` — they are live in the prod app manifest's `oauth_config.scopes.bot` — but the repo still had them commented out behind a stale "re-add once approved" TODO. Sim was therefore requesting a narrower grant than the app is entitled to, so newly connected accounts got tokens missing exactly the scopes backing three `simSubscribed` events on the native Sim app trigger: `app_mention` (app_mentions:read), assistant threads (assistant:write), and DMs (im:history). The requested scope set now matches the manifest's 20 approved bot scopes exactly. Scopes are per-credential, not per-block (one Slack app -> one `slack` provider -> one shared token, requested server-side via getCanonicalScopesForProvider), so the grant itself cannot be scoped to v2. What is per-block is what each picker advertises and treats as missing, so: - slack_v2 + the slack_oauth trigger advertise the full set (they host the native Sim app trigger that needs it). - The legacy v1 block stays pinned to the pre-expansion 17 scopes. It has no feature needing the new three, and advertising them there would flag every existing Slack credential as missing scopes and prompt a needless reconnect. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_018asmKsWQ5Vi7T7wD9uHofz --- apps/sim/blocks/blocks/slack.ts | 24 +++++++++++++++++++++++- apps/sim/lib/oauth/oauth.ts | 9 +++------ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/apps/sim/blocks/blocks/slack.ts b/apps/sim/blocks/blocks/slack.ts index 1792db96c52..0cdb2266280 100644 --- a/apps/sim/blocks/blocks/slack.ts +++ b/apps/sim/blocks/blocks/slack.ts @@ -7,6 +7,25 @@ import { normalizeFileInput } from '@/blocks/utils' import type { SlackResponse } from '@/tools/slack/types' import { getTrigger } from '@/triggers' +/** + * Scopes added for the native Sim Slack app trigger (`slack_oauth`): the shared + * app's `app_mention`, assistant-thread, and DM events don't deliver without + * them. Advertised by `slack_v2` and the trigger only — the legacy block has no + * feature that needs them, and listing them there would flag every existing + * Slack credential as missing scopes and prompt a reconnect. + * + * This only controls what each picker *advertises* and treats as missing. The + * authorization request itself is provider-wide + * (`getCanonicalScopesForProvider('slack')`), so any reconnect grants the full + * set regardless of which block started it. + */ +const SLACK_V2_ONLY_SCOPES = new Set(['app_mentions:read', 'assistant:write', 'im:history']) + +/** Slack scopes the legacy v1 block advertises — the set from before the trigger expansion. */ +const SLACK_V1_ADVERTISED_SCOPES = getScopesForService('slack').filter( + (scope) => !SLACK_V2_ONLY_SCOPES.has(scope) +) + export const SlackBlock: BlockConfig = { type: 'slack', name: 'Slack', @@ -107,7 +126,7 @@ export const SlackBlock: BlockConfig = { canonicalParamId: 'oauthCredential', mode: 'basic', serviceId: 'slack', - requiredScopes: getScopesForService('slack'), + requiredScopes: SLACK_V1_ADVERTISED_SCOPES, placeholder: 'Select Slack workspace', dependsOn: ['authMethod'], condition: { @@ -2642,6 +2661,9 @@ function adaptSubBlockForV2(sb: SubBlockConfig): SubBlockConfig { ...rest, credentialKind: 'any', placeholder: 'Select Slack account or bot', + // Full set, unlike v1: v2 hosts the native Sim app trigger, whose events + // need the mention/assistant/DM scopes. + requiredScopes: getScopesForService('slack'), credentialLabels: { oauthGroup: 'Sim app', oauthConnect: 'Connect the Sim app', diff --git a/apps/sim/lib/oauth/oauth.ts b/apps/sim/lib/oauth/oauth.ts index 99477a53525..1d74cac2b63 100644 --- a/apps/sim/lib/oauth/oauth.ts +++ b/apps/sim/lib/oauth/oauth.ts @@ -782,12 +782,9 @@ export const OAUTH_PROVIDERS: Record = { 'groups:write', 'chat:write', 'chat:write.public', - // TODO: Re-add once Slack app review approves these. Requesting a scope - // the app is not yet approved for makes Slack reject the entire - // authorization with "unapproved permissions requested", breaking connect. - // 'assistant:write', - // 'app_mentions:read', - // 'im:history', + 'assistant:write', + 'app_mentions:read', + 'im:history', 'im:write', 'im:read', 'users:read',