4.0 KiB
IM Channel Connections
DeerFlow supports user-owned IM channel connections for Telegram, Slack, and Discord. A logged-in user connects a provider from the frontend, and incoming IM messages run under that DeerFlow user account instead of the raw platform user id.
Configuration
Enable the top-level channel_connections block in config.yaml:
channel_connections:
enabled: true
public_base_url: https://deerflow.example.com
encryption_key: $DEER_FLOW_CHANNEL_CONNECTIONS_KEY
telegram:
enabled: true
bot_token: $TELEGRAM_BOT_TOKEN
bot_username: $TELEGRAM_BOT_USERNAME
webhook_secret: $TELEGRAM_WEBHOOK_SECRET
slack:
enabled: true
client_id: $SLACK_CLIENT_ID
client_secret: $SLACK_CLIENT_SECRET
signing_secret: $SLACK_SIGNING_SECRET
event_delivery: http
discord:
enabled: true
client_id: $DISCORD_CLIENT_ID
client_secret: $DISCORD_CLIENT_SECRET
bot_token: $DISCORD_BOT_TOKEN
permissions: "274877975552"
public_base_url must be the externally reachable HTTPS origin used by provider callbacks and webhooks. encryption_key encrypts provider tokens at rest with Fernet. Keep it stable; v1 does not support transparent key rotation, so changing it requires users to reconnect.
Frontend Flow
The workspace sidebar shows a Channels group with Telegram, Slack, and Discord. Settings > Channels exposes the management surface for connect, disconnect, and reconnect. Browser state-changing calls use the existing CSRF-aware frontend fetch wrapper.
Provider Setup
Telegram:
- Register a bot with BotFather.
- Configure the bot username, bot token, and a random webhook secret.
- Users connect with a deep link:
https://t.me/<bot_username>?start=<state>. - Production webhook path:
POST /api/channels/webhooks/telegram, protected byX-Telegram-Bot-Api-Secret-Token. - Local/self-hosted long polling still works through the existing Telegram channel worker.
Slack:
- Create a Slack app with OAuth V2.
- Redirect URL:
https://<public_base_url>/api/channels/slack/callback. - Event request URL:
https://<public_base_url>/api/channels/webhooks/slack/events. - Required signing secret: Slack's request signing secret, not the deprecated verification token.
- Suggested MVP bot scopes:
app_mentions:read,chat:write,channels:history,channels:read. - Slack events are signature-verified, deduplicated by
event_id, and then routed to a matching user connection.
Discord:
- Create a Discord application and bot.
- Redirect URL:
https://<public_base_url>/api/channels/discord/callback. - DeerFlow starts OAuth with
identify guilds bot applications.commandsand the configured bot permissions. - The Discord Gateway is still handled by
discord.py; message content may require the privileged Message Content Intent depending on your bot setup.
Runtime Model
Connection records live in SQL tables under deerflow.persistence.channel_connections:
channel_connections: owner user, provider identity, workspace/guild/team, status, metadata.channel_credentials: encrypted access/refresh/bot tokens.channel_oauth_states: one-time OAuth/deep-link states.channel_conversations: connection-scoped IM conversation to DeerFlow thread mapping.channel_webhook_deliveries: provider webhook dedupe records.
Incoming messages that resolve to a connection carry connection_id, owner_user_id, and workspace_id. ChannelManager uses owner_user_id as the DeerFlow run user id and preserves the platform user id as channel_user_id. Legacy operator-owned channels keep the existing JSON ChannelStore behavior when no connection_id is present.
Security Notes
- OAuth state tokens are one-time and short-lived.
- Provider tokens are never returned from browser APIs.
- Public callback/webhook routes bypass cookie auth only because they validate provider state/signatures/secrets themselves.
- Slack and Telegram webhooks skip CSRF because they are called by providers, not browsers.
- Logs should never include access tokens, refresh tokens, bot tokens, OAuth codes, or raw signed webhook bodies.