Skip to main content

Slack

The Slack channel lets a tenant install Orbit into their own Slack workspace as a Slack App. Operators connect the workspace through the OAuth v2 authorize → callback flow; inbound Events API messages, slash commands, and interactivity payloads are POSTed back to Orbit and verified with the App’s signing secret.
This is the tenant-facing Slack App — distinct from the internal ops-alert webhook (DEVOTEL_SLACK_OPS_WEBHOOK_URL), which only posts Orbit’s own operational alerts to a Devotel-internal channel.

Operator setup

Configure the Slack App credentials once per deployment, in Secret Manager (or .env for local dev). All four variables are optional at boot; the Slack channel stays disabled until they are set.
VariableRequiredPurpose
DEVOTEL_SLACK_CLIENT_IDTo enable installSlack App OAuth v2 client id. Used to build the https://slack.com/oauth/v2/authorize URL.
DEVOTEL_SLACK_CLIENT_SECRETTo enable installSlack App OAuth v2 client secret. Used (HTTP Basic, with the client id) to redeem the temporary code at https://slack.com/api/oauth.v2.access.
DEVOTEL_SLACK_SIGNING_SECRETTo accept inboundHMAC-SHA256 key that verifies inbound Events / slash-command / interactivity requests. Fail-closed (see below).
DEVOTEL_SLACK_BOT_SCOPESOptionalComma-separated OAuth v2 bot scopes requested at install. Defaults to the baseline set baked into packages/shared/src/env.ts; override only if the App adds optional scopes (e.g. assistant:write).
In your Slack App configuration (api.slack.com/apps), find the client id + secret under Basic Information → App Credentials, and the signing secret on the same screen. Set the Slack App’s Redirect URL to:
https://api.orbit.devotel.io/api/v1/integrations/slack/oauth/callback

Default bot scopes

If DEVOTEL_SLACK_BOT_SCOPES is unset, Orbit requests the following baseline scopes:
chat:write, chat:write.public, commands, app_mentions:read,
channels:history, channels:read, groups:history, groups:read,
im:history, im:write, users:read, users:read.email,
reactions:read, links:read, files:write

Install flow (OAuth v2)

  1. From the dashboard, navigate to Channels → Slack and click Connect Workspace. This calls the authenticated start route, which mints an HMAC-signed state token and redirects the operator’s browser to Slack’s authorize screen.
    GET /api/v1/integrations/slack/oauth/start
    
  2. The operator approves the requested bot scopes in Slack.
  3. Slack redirects the browser (a top-level navigation) back to the public callback route, which verifies the signed state, resolves the tenant from the verified payload, redeems the temporary code, and stores the workspace credentials in the tenant schema.
    GET /api/v1/integrations/slack/oauth/callback
    
The callback is intentionally registered before Clerk auth (public scope) because browsers do not reliably carry the session cookie across Slack’s cross-site redirect. Trust is anchored on the HMAC-signed state round-trip, not on a session cookie.

Inbound request verification

Point your Slack App’s Event Subscriptions, Slash Commands, and Interactivity Request URLs at either of the equivalent inbound endpoints:
POST /api/v1/integrations/webhooks/slack    (canonical)
POST /api/v1/webhooks/slack/events          (Slack-convention alias)
Both mounts share one handler — the same signature gate, tenant resolution, and dispatch. Orbit verifies every inbound request per Slack’s verifying-requests-from-slack spec:
X-Slack-Signature: v0=<hex>
where  v0  = HMAC-SHA256(DEVOTEL_SLACK_SIGNING_SECRET, "v0:" + X-Slack-Request-Timestamp + ":" + rawBody)
The request timestamp (X-Slack-Request-Timestamp) must be within 5 minutes of now (Slack’s documented replay-protection window).

Fail-closed behaviour

Per platform invariant #29 the receiver fails closed:
DEVOTEL_SLACK_SIGNING_SECRETInbound requestResult
SetValid signature, fresh timestamp200 — processed
SetBad/missing signature, or timestamp older than 5 min401 — rejected
UnsetAny503 — channel disabled (never accept unsigned events)
So an operator must set the signing secret before enabling the Slack channel; otherwise inbound deliveries return 503 and Slack will disable the subscription after repeated non-200s.

Common errors

SymptomCauseFix
Install returns 503 from /startDEVOTEL_SLACK_CLIENT_ID / DEVOTEL_SLACK_CLIENT_SECRET unsetSet the App credentials in Secret Manager and redeploy.
Inbound events return 503DEVOTEL_SLACK_SIGNING_SECRET unsetSet the signing secret before enabling the channel.
Inbound events return 401Signing-secret mismatch or stale timestamp (clock skew > 5 min)Re-copy the signing secret from Basic Information; verify host clock (NTP).
Slack disabled the subscriptionRepeated non-200s on the Request URLFix the secret, then re-enable Event Subscriptions in the Slack App.