Skip to content

Commit 8b9129b

Browse files
alpetrichcourdent
andauthored
Alp/slack updates (#1136)
* fix: broken oidc page * feat: slack @ commands + workspace specific slack * changelog * pic --------- Co-authored-by: Henri Courdent <122811744+hcourdent@users.noreply.github.com>
1 parent 06cc15e commit 8b9129b

File tree

5 files changed

+229
-5
lines changed

5 files changed

+229
-5
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
slug: slack-mention-triggers
3+
version: v1.567.0
4+
title: Slack @mention triggers
5+
tags: ['Integrations', 'Slack', 'Triggers']
6+
description: Trigger Windmill scripts by @mentioning the Windmill bot in Slack channels, threads, or direct messages - in addition to slash commands.
7+
features:
8+
[
9+
'Trigger scripts with @Windmill in public channels, private channels, DMs, and threads',
10+
'Use the same handler script for both /windmill commands and @mentions',
11+
'Bot mention is automatically stripped from text before passing to handler',
12+
'Distinguish between triggers using the command parameter (@mention vs /windmill)',
13+
'Respond to slash commands using response_url webhook',
14+
'Respond to @mentions using Slack Web API with bot token',
15+
]
16+
docs: /docs/integrations/slack#using-mentions
17+
---
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
slug: workspace-slack-oauth
3+
version: v1.567.0
4+
title: Workspace-level Slack app configuration
5+
tags: ['Integrations', 'Slack', 'OAuth']
6+
description: Workspace admins can now configure their own Slack app with workspace-specific OAuth credentials for better isolation and independent management.
7+
features:
8+
[
9+
'Configure workspace-specific Slack app credentials (Client ID and Secret)',
10+
'Workspace isolation with separate Slack apps per workspace',
11+
'Independent rate limits per workspace',
12+
'Automatic fallback to instance-level configuration when not configured',
13+
'Applies to f/slack_bot/bot_token resource for workspace handlers and Slack approvals',
14+
]
15+
docs: /docs/integrations/slack#workspace-level-slack-app-configuration
16+
image: ./workspace-slack.png
17+
---
57.9 KB
Loading

docs/integrations/slack.mdx

Lines changed: 171 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ The Slack integration is done through OAuth. On [self-hosted instances](../advan
4242

4343
:::
4444

45+
:::tip Workspace-level configuration
46+
47+
By default, the OAuth flow uses instance-level Slack app credentials configured by your administrator. Workspace admins can also [configure their own Slack app](#workspace-level-slack-app-configuration) with workspace-specific credentials for better isolation and independent management.
48+
49+
:::
50+
4551
Slack will ask you to allow Windmill to access your workspace. Click "Allow".
4652

4753
<video
@@ -95,7 +101,7 @@ the `/windmill` command in your Slack workspace to trigger the Script. Try it
95101
out with `/windmill foo` and you should get back `ROGER foo`. Go ahead and
96102
customize the Script to your needs.
97103

98-
In addition to response_url, the script/flow can use the following parameters, simply by having them as inputs with the proper name:
104+
In addition to `response_url`, the script/flow can use the following parameters, simply by having them as inputs with the proper name:
99105

100106
```
101107
channel_id
@@ -108,6 +114,170 @@ api_app_id
108114

109115
![Use the Windmill command](../assets/integrations/slack-5-slack-command.png.webp)
110116

117+
### Using @mentions
118+
119+
In addition to slash commands, you can trigger your Windmill scripts by @mentioning the Windmill bot in any channel, thread, or direct message. @mentions work identically to `/windmill` commands - they use the same handler script configured in your workspace settings and pass the same parameters.
120+
121+
When you @mention the bot (e.g., `@Windmill hello world`), the bot mention is automatically stripped from the text before being passed to your handler script, so it receives just `hello world` - identical to how `/windmill hello world` would work.
122+
123+
@mentions work in:
124+
- Public channels (when the bot is invited to the channel)
125+
- Private channels (when the bot is invited)
126+
- Direct messages with the bot
127+
- Message threads (reply to any message and @mention the bot)
128+
129+
The `command` parameter will be set to `@mention` for @mention triggers (vs `/windmill` for slash commands), allowing your handler to distinguish between the two if needed.
130+
131+
Available parameters for @mention triggers:
132+
133+
```
134+
text // Message text with bot mention stripped
135+
channel_id // Channel where message was sent
136+
user_id // Slack user ID who sent the message
137+
command // Set to "@mention" for @mentions
138+
event_id // Unique event identifier
139+
ts // Message timestamp
140+
thread_ts // Thread timestamp (if in a thread)
141+
```
142+
143+
:::note
144+
@mentions are delivered via Slack's Events API, which means your handler must respond within 3 seconds. For longer-running operations, launch a job and send updates to Slack asynchronously using the Slack API.
145+
:::
146+
147+
#### Responding to `/` commands vs `@` mentions
148+
149+
When handling Slack triggers, the response method differs depending on the trigger type:
150+
151+
**For `/windmill` slash commands**: Use the `response_url` parameter (a webhook URL) to send your response back to Slack.
152+
153+
**For `@mention` triggers**: Use the Slack Web API with the bot token to post messages to the channel.
154+
155+
<Tabs className="unique-tabs">
156+
<TabItem value="deno" label="Deno" attributes={{className: "text-xs p-4 !mt-0 !ml-0"}}>
157+
158+
```typescript
159+
import { WebClient } from 'https://deno.land/x/slack_web_api@1.0.3/mod.ts';
160+
import * as wmill from 'https://deno.land/x/windmill@v1.85.0/mod.ts';
161+
162+
type Slack = {
163+
token: string;
164+
};
165+
166+
export async function main(
167+
text: string,
168+
response_url: string,
169+
channel_id: string,
170+
command: string
171+
) {
172+
const responseText = `You said: ${text}`;
173+
174+
if (command === '@mention') {
175+
// For @mentions: use Slack Web API
176+
const slack = await wmill.getResource<Slack>('f/slack_bot/bot_token');
177+
const web = new WebClient(slack.token);
178+
await web.chat.postMessage({
179+
channel: channel_id,
180+
text: responseText
181+
});
182+
} else {
183+
// For /windmill commands: use response_url
184+
await fetch(response_url, {
185+
method: 'POST',
186+
body: JSON.stringify({ text: responseText })
187+
});
188+
}
189+
}
190+
```
191+
192+
</TabItem>
193+
194+
<TabItem value="bun" label="Bun" attributes={{className: "text-xs p-4 !mt-0 !ml-0"}}>
195+
196+
```typescript
197+
import { WebClient } from '@slack/web-api';
198+
import * as wmill from 'windmill-client';
199+
200+
type Slack = {
201+
token: string;
202+
};
203+
204+
export async function main(
205+
text: string,
206+
response_url: string,
207+
channel_id: string,
208+
command: string
209+
) {
210+
const responseText = `You said: ${text}`;
211+
212+
if (command === '@mention') {
213+
// For @mentions: use Slack Web API
214+
const slack = await wmill.getResource<Slack>('f/slack_bot/bot_token');
215+
const web = new WebClient(slack.token);
216+
await web.chat.postMessage({
217+
channel: channel_id,
218+
text: responseText
219+
});
220+
} else {
221+
// For /windmill commands: use response_url
222+
await fetch(response_url, {
223+
method: 'POST',
224+
body: JSON.stringify({ text: responseText })
225+
});
226+
}
227+
}
228+
```
229+
230+
</TabItem>
231+
232+
<TabItem value="python" label="Python" attributes={{className: "text-xs p-4 !mt-0 !ml-0"}}>
233+
234+
```python
235+
from slack_sdk import WebClient
236+
import wmill
237+
import requests
238+
import json
239+
240+
def main(text: str, response_url: str, channel_id: str, command: str):
241+
response_text = f"You said: {text}"
242+
243+
if command == "@mention":
244+
# For @mentions: use Slack Web API
245+
slack = wmill.get_resource("f/slack_bot/bot_token")
246+
client = WebClient(token=slack["token"])
247+
client.chat_postMessage(
248+
channel=channel_id,
249+
text=response_text
250+
)
251+
else:
252+
# For /windmill commands: use response_url
253+
requests.post(
254+
response_url,
255+
data=json.dumps({"text": response_text}),
256+
headers={"Content-Type": "application/json"}
257+
)
258+
```
259+
260+
</TabItem>
261+
</Tabs>
262+
263+
### Workspace-level Slack app configuration
264+
265+
By default, workspaces use the instance-level Slack app configured by your Windmill administrator. However, workspace admins can optionally configure their own Slack app for their workspace. This provides:
266+
267+
- **Workspace isolation**: Each workspace uses its own Slack app and credentials
268+
- **Separate rate limits**: Avoid sharing rate limits across workspaces
269+
- **Independent management**: Workspace admins can manage their own Slack integration
270+
271+
To configure a workspace-specific Slack app:
272+
273+
1. Navigate to workspace settings → Slack app section
274+
2. Enter your Slack app's **Client ID** and **Client Secret**
275+
3. Save the configuration
276+
277+
:::note
278+
The workspace-level Slack app will only apply to the auomatically managed `f/slack_bot/bot_token` resource used for workspace handlers and slack approvals. For general user specific slack oauth tokens, the instance level OAuth connection will be used.
279+
:::
280+
111281
You won't be able to have Slack interact with your [resources](../core_concepts/3_resources_and_types/index.mdx) and [variables](../core_concepts/2_variables_and_secrets/index.mdx) before adding them to the `slack` [group](../core_concepts/8_groups_and_folders/index.mdx#groups) that was automatically created by Windmill after you set up your Slack workspace on Windmill. Tutorial below.
112282

113283
<details>

docs/misc/2_setup_oauth/index.mdx

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,12 +258,13 @@ Pick "From an app manifest", then YAML.
258258

259259
![Slack Create App](./slack_create_app.png 'Slack Create App')
260260

261-
Your app manifest should look like this, replacing `<YOUR INSTANCE URL>` in 3 places:
261+
Your app manifest should look like this, replacing `<YOUR INSTANCE URL>` in 4 places:
262262

263263
:::warning
264-
`<YOUR INSTANCE URL>/api/oauth/slack_command` must be reachable from the public internet for the Slack command to work.
265-
266-
`<YOUR INSTANCE URL>/api/slack` must be reachable from the public internet for interactive approvals to work.
264+
These URLs must be publicly accessible:
265+
- `<YOUR INSTANCE URL>/api/oauth/slack_command` - for slash commands
266+
- `<YOUR INSTANCE URL>/api/oauth/slack_events` - for @mention triggers
267+
- `<YOUR INSTANCE URL>/api/slack` - for interactive approvals
267268
:::
268269

269270
```yaml
@@ -300,7 +301,15 @@ oauth_config:
300301
- channels:join
301302
- files:write
302303
- commands
304+
- app_mentions:read
305+
- im:history
306+
- im:read
303307
settings:
308+
event_subscriptions:
309+
request_url: <YOUR INSTANCE URL>/api/oauth/slack_events
310+
bot_events:
311+
- app_mention
312+
- message.im
304313
interactivity:
305314
is_enabled: true
306315
request_url: <YOUR INSTANCE URL>/api/slack
@@ -323,6 +332,17 @@ Now users should be able to connect to Slack through OAuth:
323332
324333
![Slack Connect](./slack_connect.png 'Slack Connect')
325334
335+
#### Workspace-level Slack app
336+
337+
In addition to instance-level configuration, workspace admins can configure their own Slack app with workspace-specific credentials. This provides workspace isolation, separate rate limits, and independent management.
338+
339+
To enable workspace-level Slack apps:
340+
1. Follow the same app manifest setup above to create a Slack app
341+
2. In workspace settings, navigate to the Slack app section
342+
3. Enter the workspace-specific Client ID and Client Secret
343+
344+
When configured, the workspace will use its own Slack app instead of the instance-level app. See the [Slack integration documentation](../../integrations/slack.mdx#workspace-level-slack-app-configuration) for more details on workspace-level configuration and when to use it.
345+
326346
### Microsoft Teams
327347
- Go to the [Azure Portal](https://portal.azure.com/) and create a new "Bot Service" of type "[Azure Bot](https://portal.azure.com/#create/Microsoft.AzureBot)".
328348
![Azure Bot Service](./azure_bot_service.png 'Azure Bot Service')

0 commit comments

Comments
 (0)