Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,12 @@
"enterprise/k8s-install/index",
"enterprise/k8s-install/resource-limits"
]
},
{
"group": "Integrations",
"pages": [
"enterprise/integrations/slack"
]
}
]
}
Expand Down
385 changes: 385 additions & 0 deletions enterprise/integrations/slack.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,385 @@
---
title: Slack
description: Configure the Slack integration for a self-hosted OpenHands Enterprise install.
icon: slack
---

This guide walks an operator through enabling the `@OpenHands` Slack integration on a
self-hosted **OpenHands Enterprise (OHE)** installation — both the Replicated VM-based
install (see the [Quick Start](/enterprise/quick-start)) and standalone Helm
([Kubernetes Installation](/enterprise/k8s-install/index)).

Once enabled, end users can mention `@openhands` in any Slack channel or thread to start
and follow up on conversations from Slack, exactly like they can on OpenHands Cloud.

<Info>
If you are looking for the **OpenHands Cloud** Slack integration (no self-hosting
involved), see [Slack Integration](/openhands/usage/cloud/slack-installation)
instead — that page uses the All-Hands-managed Slack App and skips the steps below.
</Info>

## Overview

Unlike OpenHands Cloud, a self-hosted install needs its **own** Slack App so that Slack
webhooks land on *your* domain rather than `app.all-hands.dev`. The configuration involves
four phases:

1. **Create a Slack App** for your install (one-time, by a Slack workspace admin).
2. **Configure OHE** with the Slack App's credentials (one-time, by the OHE operator).
3. **Install the Slack App** into your workspace (one-time, by a Slack workspace admin).
4. **Link each user's account** in OpenHands ↔ Slack (per-user, self-service).

<Steps>
<Step title="Verify prerequisites" />
<Step title="Create the Slack App" />
<Step title="Configure OpenHands Enterprise" />
<Step title="Install the Slack App into your workspace" />
<Step title="Have users link their Slack accounts" />
</Steps>

## Prerequisites

Before you start, confirm:

- **OHE is already installed and reachable.** You can sign in to OpenHands Enterprise at
`https://app.<your-base-domain>` (e.g. `https://app.mycompany.com`).
- **Inbound HTTPS from the public internet** terminates at your OHE ingress on
`https://app.<your-base-domain>/slack/*`. Slack delivers webhooks from public IPs, so

Check warning on line 47 in enterprise/integrations/slack.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/integrations/slack.mdx#L47

Did you really mean 'IPs'?
fully air-gapped installs are **not** supported by this integration today (Slack Socket
Mode is disabled).
- **Valid TLS certificate** on `app.<your-base-domain>`. Slack will reject webhook URLs
with untrusted certificates.

Check warning on line 51 in enterprise/integrations/slack.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/integrations/slack.mdx#L51

Did you really mean 'untrusted'?
- **A Slack workspace admin/owner** is available to install the app and generate a
short-lived Slack App Configuration Token.
- **A workstation with `uv` installed** and outbound network access to `slack.com` (only
needed for the optional helper script in Step 2).

<Note>
Replace `<your-base-domain>` throughout this guide with the same domain you used during
installation (the value behind `KOTS_HOSTNAME` or the `ingress.host` Helm value).
</Note>

## Step 1: Create the Slack App

You can mint the Slack App either with the helper script in
[`OpenHands-Cloud`](https://github.com/OpenHands/OpenHands-Cloud) (recommended) or by
pasting the manifest into Slack's UI. Either path produces the same app.

### Option A: Helper script (recommended)

1. Generate a **Slack App Configuration Token**:

1. Sign in to [https://api.slack.com/apps](https://api.slack.com/apps) as a workspace
admin/owner.
2. In **Your App Configuration Tokens**, click **Generate Token**.
3. Select your workspace and click **Generate**.
4. Copy the **access token** (starts with `xoxe.xoxp-`). Treat it like a password —
it is short-lived but is sufficient to create apps in your workspace.

2. Clone OpenHands-Cloud and run the script:

```bash
git clone https://github.com/OpenHands/OpenHands-Cloud.git
cd OpenHands-Cloud

export SLACK_CONFIG_TOKEN=xoxe.xoxp-...
./scripts/create_slack_app/create_slack_app.py \
--base-domain <your-base-domain>
```

<Tip>
Pass `--dry-run` to print what would be created without calling Slack. Pass
`--app-name "OpenHands (Staging)"` to differentiate multiple installs in the same
workspace.
</Tip>

3. The script prints three values. **Save them now** — Slack will let you retrieve them
again from the app's "Basic Information" page, but the script does not store them
anywhere:

```
Slack Client ID: ...
Slack Client Secret: ...
Slack Signing Secret: ...
```

The script registers the following URLs on the new Slack App (all rooted at
`https://app.<your-base-domain>`):

| Slack setting | URL |
|---|---|
| OAuth Redirect URL | `/slack/install-callback` |
| Event Subscriptions Request URL | `/slack/on-event` |
| Interactivity Request URL | `/slack/on-form-interaction` |
| Options Load URL | `/slack/on-options-load` |

…and requests these bot scopes (no user scopes):

`app_mentions:read`, `chat:write`, `users:read`, `channels:history`,
`groups:history`, `mpim:history`, `im:history`.

Socket Mode, Org Deploy, and Token Rotation are intentionally **disabled** to match
what the OHE backend expects today.

### Option B: Paste the manifest into Slack's UI

If you can't run the script (e.g. your workstation has no outbound Slack access), open
[https://api.slack.com/apps](https://api.slack.com/apps) → **Create New App** → **From an
app manifest**, choose your workspace, and paste the YAML below. Replace
`<your-base-domain>` first.

```yaml
display_information:
name: OpenHands
features:
bot_user:
display_name: OpenHands
always_online: false
oauth_config:
redirect_urls:
- https://app.<your-base-domain>/slack/install-callback
scopes:
bot:
- app_mentions:read
- chat:write
- users:read
- channels:history
- groups:history
- mpim:history
- im:history
settings:
event_subscriptions:
request_url: https://app.<your-base-domain>/slack/on-event
bot_events:
- app_mention
interactivity:
is_enabled: true
request_url: https://app.<your-base-domain>/slack/on-form-interaction
message_menu_options_url: https://app.<your-base-domain>/slack/on-options-load
org_deploy_enabled: false
socket_mode_enabled: false
token_rotation_enabled: false
```

After creating the app, copy **Client ID**, **Client Secret**, and **Signing Secret**
from the app's **Basic Information** page.

<Warning>
When Slack verifies your **Event Subscriptions Request URL**, your OHE install must
already be reachable at `https://app.<your-base-domain>/slack/on-event`. If you create
the Slack App before OHE is running, Slack will mark the URL as unverified and you'll
need to click "Retry" after finishing Step 3.
</Warning>

## Step 2: Configure OpenHands Enterprise

Pick the path that matches how OHE is deployed.

<Tabs>
<Tab title="Replicated (VM/embedded cluster)">
1. Open the Replicated admin console at
`https://<admin-console-host>:30000` and sign in.
2. Navigate to **Config → Enable Slack** (or search "Slack" in the config side panel).
3. Set the following values:

| Field | Value |
|---|---|
| **Enable Slack Integration** | ✅ on |
| **Slack Client ID** | from Step 1 |
| **Slack Client Secret** | from Step 1 |
| **Slack Signing Secret** | from Step 1 |

4. Click **Save config** and then **Deploy** the new version.
5. Wait for the deployment to reach **Ready** — Replicated will roll the integrations
pod with the new secrets and environment variables.

Behind the scenes this:

- Creates a Kubernetes `Secret/slack-auth` holding the client and signing secrets.
- Sets `slack.enabled=true`, `slack.clientId=<client-id>`, and
`ENABLE_V1_SLACK_RESOLVER=true` on the integrations service.
- Exposes `/slack/*` on the integrations ingress on port 3000.

</Tab>
<Tab title="Standalone Helm">
Set the Slack values directly on the `openhands` and `openhands-secrets` charts.

In your `values.yaml` for the `openhands` chart:

```yaml
slack:
enabled: true
clientId: "<your-slack-client-id>"

env:
ENABLE_V1_SLACK_RESOLVER: "true"
```

In your `values.yaml` for the `openhands-secrets` chart:

```yaml
config:
slack_client_id: "<your-slack-client-id>"
slack_client_secret: "<your-slack-client-secret>"
slack_signing_secret: "<your-slack-signing-secret>"
```

Then redeploy:

```bash
helm upgrade --install openhands-secrets ./charts/openhands-secrets \
-f values-secrets.yaml -n openhands

helm upgrade --install openhands ./charts/openhands \
-f values.yaml -n openhands
```

<Tip>
If you manage the secret yourself, you can skip the `openhands-secrets` chart and
create a `Secret/slack-auth` directly with keys `client-id`, `client-secret`, and
`signing-secret`. The deployment reads `client-secret` and `signing-secret` from
that secret, and reads `client-id` from the `slack.clientId` Helm value.
</Tip>

</Tab>
</Tabs>

Confirm the integrations pod restarted with the new environment:

```bash
kubectl -n openhands set env deployment/openhands-integrations --list \
| grep '^SLACK_'
```

You should see `SLACK_CLIENT_ID`, `SLACK_CLIENT_SECRET`, `SLACK_SIGNING_SECRET`, and
`SLACK_WEBHOOKS_ENABLED=true`.

## Step 3: Install the Slack App into your workspace

With OHE configured, point your browser at:

```
https://app.<your-base-domain>/slack/install
```

This redirects through Slack's OAuth v2 flow and then through OpenHands' Keycloak login.

Check warning on line 265 in enterprise/integrations/slack.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/integrations/slack.mdx#L265

Did you really mean 'Keycloak'?
A workspace admin/owner should complete this step **first** — they will be granting
the OpenHands bot permission to read mentions and post messages in your workspace.

After approval you'll see **OpenHands Authentication Successful!** Slack will also mark
the Event Subscriptions Request URL as verified.

<Note>
If Slack reports `missing_scope` after install, the most likely cause is that the
manifest was edited to drop one of the `*:history` scopes. Re-run Step 1 (or fix the
scopes in the Slack App **OAuth & Permissions** page) and then re-install via the
same URL.
</Note>

## Step 4: Have users link their Slack accounts

`@OpenHands` will only respond to users whose Slack identity has been linked to an
OpenHands user. Every user — including the admin who installed the app — needs to do
this once. They have two options:

- **From OpenHands**: sign in at `https://app.<your-base-domain>`, open
**Settings → Integrations**, and click **Install OpenHands Slack App**.
- **From Slack**: the first time they mention `@openhands`, the bot will reply with a
one-time login link that completes the same flow.

Either path produces the same record in the `slack_users` table, mapping the Slack user
ID to a Keycloak (OpenHands) user. Once linked, any conversation started from Slack runs

Check warning on line 291 in enterprise/integrations/slack.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/integrations/slack.mdx#L291

Did you really mean 'Keycloak'?
as that OpenHands user — using their LLM keys, provider tokens, and organization.

## Using the integration

Day-to-day usage is identical to OpenHands Cloud — see
[Working With the Slack App](/openhands/usage/cloud/slack-installation#working-with-the-slack-app)
for screenshots and the "mention `@openhands` in a thread" follow-up flow.

A few self-hosted specifics worth knowing:

- **Repo selection.** When a user starts a new conversation without an obvious repo in
the message, OpenHands posts an ephemeral repo picker. The picker calls back to
`/slack/on-options-load` on your domain and lists repositories the user can access
through their linked Git provider.
- **Thread ownership.** Only the user who started a thread conversation can `@openhands`
in follow-up replies — other workspace members mentioning the bot in the same thread
will get an "not authorized to send messages to this conversation" response. This is
intentional until per-org access lands.
- **Conversation links.** The bot's "I'm on it!" reply links to

Check warning on line 310 in enterprise/integrations/slack.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/integrations/slack.mdx#L310

Did you really mean 'bot's'?
`https://app.<your-base-domain>/conversations/<id>`. Users must be signed in to OHE
to view it.

## Limitations

- **No Slack Socket Mode.** Your OHE install must be reachable from the public internet
on `https://app.<your-base-domain>/slack/*`. Air-gapped installs cannot use this
integration today.
- **No token rotation.** The bot uses a long-lived `xoxb-` token issued at install time.
If you regenerate the Slack App's credentials, re-run Steps 2 and 3.
- **Single Slack App per install.** The OHE backend assumes one Slack App per
deployment. To support multiple workspaces, install the **same** Slack App into each
workspace via Step 3 — do not create separate apps.
- **Slack Connect / externally shared channels** are not supported for posting from the
bot.

## Troubleshooting

<AccordionGroup>
<Accordion title="Slack reports 'Your URL didn't respond with the value of the challenge parameter'">
Slack could not reach `https://app.<your-base-domain>/slack/on-event` from the
public internet, or the TLS certificate isn't trusted. Verify from a machine outside
your network:

```bash
curl -i https://app.<your-base-domain>/slack/on-event
```

You should get an HTTP response (a 403 is expected and fine — it means the route
exists). If the request times out or the certificate is rejected, fix DNS / firewall
/ TLS before clicking **Retry** in Slack's Event Subscriptions panel.
</Accordion>

<Accordion title="`@openhands` mentions are ignored">
1. Check that `SLACK_WEBHOOKS_ENABLED=true` is set on the integrations pod. If it is
missing, your OHE deployment did not re-roll after Step 2 — redeploy.
2. Tail the integrations pod logs and mention `@openhands` again. You should see a
`slack_on_event` log line. If you don't, Slack isn't reaching your install.
3. If you see `slack_on_event` followed by `slack_is_duplicate`, Slack is retrying
an old delivery — wait 60 seconds and try a fresh message.
</Accordion>

<Accordion title="Users get a login link every time they mention @openhands">
The user's Slack ID is not linked to an OpenHands user. Have them complete Step 4
once. If they have already linked but still see the login prompt, check that their
Keycloak user is active and that the `slack_users` row exists:

Check warning on line 356 in enterprise/integrations/slack.mdx

View check run for this annotation

Mintlify / Mintlify Validation (allhandsai) - vale-spellcheck

enterprise/integrations/slack.mdx#L356

Did you really mean 'Keycloak'?

```bash
kubectl -n openhands exec -it deployment/openhands-postgres -- \
psql -U postgres -d openhands -c \
"SELECT slack_user_id, keycloak_user_id FROM slack_users;"
```
</Accordion>

<Accordion title="`missing_scope` error in pod logs">
The Slack App is missing one of the bot scopes listed in Step 1. Open the app's
**OAuth & Permissions** page in Slack, add the missing scope, then re-install via
`https://app.<your-base-domain>/slack/install`. Users do **not** need to re-link.
</Accordion>

<Accordion title="Re-installing after rotating Slack credentials">
1. Regenerate the Slack App's Client Secret / Signing Secret on Slack's app config
page.
2. Update them in Step 2 (Replicated admin console **or** the Helm secret).
3. Redeploy OHE so the integrations pod picks up the new values.
4. Existing user account links remain valid — no need to re-run Step 4.
</Accordion>
</AccordionGroup>

## Reference

- Helper script: [`scripts/create_slack_app/`](https://github.com/OpenHands/OpenHands-Cloud/tree/main/scripts/create_slack_app) in `OpenHands-Cloud`
- Replicated config group: [`replicated/config.yaml`](https://github.com/OpenHands/OpenHands-Cloud/blob/main/replicated/config.yaml) (`slack_configuration`)
- Helm chart values: [`charts/openhands/values.yaml`](https://github.com/OpenHands/OpenHands-Cloud/blob/main/charts/openhands/values.yaml) (`slack.*`)
- Cloud-hosted Slack flow (for end-user UX reference): [Slack Integration](/openhands/usage/cloud/slack-installation)
Loading
Loading