Skip to content

Slack Integration

Connect WhiteLotusAI to Slack to discover accessible channels and retrieve recent conversations through registered integration tools.

Warning

Release status: Not approved for production read-only use.

The repository contains channel-reading and message-posting capabilities. The initial release must enforce a server-side read-only policy, remove unnecessary write scopes, and resolve shared-token fallback behavior before production approval.

Slack API documentation · Slack OAuth documentation · Slack permissions


1. Overview

The Slack integration connects a user's Slack workspace to WhiteLotusAI through OAuth 2.0. The chat service selects registered tools, while the integrations service resolves credentials and communicates with the Slack Web API.

The initial release is intended to be read-only.

Supported capabilities

  • List public and private channels accessible to the connected Slack identity.
  • Retrieve recent messages from a specified channel.
  • Establish a Slack connection through OAuth 2.0.
  • Normalize provider responses for consumption by the chat service.

Message posting is present in the source code but must remain unavailable in the initial release.

Implementation status

Capability Source-level status Release requirement
OAuth connection Implemented Verify state validation, identity binding, and token storage
Channel listing Implemented Enforce user isolation and verify pagination behavior
Channel history Implemented Validate channel access and bound request limits
Message posting Implemented Block before provider invocation
Per-user token resolution Present Remove unsafe shared-token fallback in per-user mode
Rate-limit handling Incomplete or requires verification Implement and test provider-aware retry behavior

Note

This page documents the implementation findings supplied from the repository review. It does not certify successful end-to-end tests, deployment configuration, or production security controls.

2. Registered tools

The chat plugin is located at chat/package/app/plugins/slack/plugin.py.

Tool Category Purpose Initial release
list_channels READ List accessible Slack channels Allowed after authorization
get_channel_history READ Retrieve recent channel messages Allowed after authorization
send_message WRITE Post a message to a Slack channel Blocked

The send_message tool has a confirmation requirement and a configured rate limit of 10. Neither mechanism establishes a read-only security boundary.

The plugin's intent-routing logic recognizes Slack-related phrases and channel names such as #general. Requests containing words such as “send,” “post,” “notify,” or “message” may be routed to the write tool.

Security rule: conversational instructions, tool descriptions, confirmation prompts, and rate limits must never substitute for server-side authorization.

3. Architecture and request flow

The integration spans the chat plugin, tool registry, integrations service, credential resolver, and Slack Web API client.

flowchart TD
    U["User request"] --> C["Chat service"]
    C --> P["Intent and tool selection"]
    P --> R{"Registered tool allowed?"}
    R -->|No| D["Reject operation"]
    R -->|Yes| A["Authenticate internal request"]
    A --> I["Integrations service"]
    I --> V{"Valid user connection and token?"}
    V -->|No| X["Fail closed"]
    V -->|Yes| S["Slack API client"]
    S --> W["Slack Web API"]
    W --> N["Normalize response"]
    N --> C

    R -.->|Write tool| B["Read-only policy gate"]
    B --> D

    classDef process fill:#E8F0FE,stroke:#315DA8,color:#172B4D,stroke-width:1.5px
    classDef decision fill:#FFF0CC,stroke:#9A6700,color:#513600,stroke-width:1.5px
    classDef safe fill:#DDF5E8,stroke:#238454,color:#12452D,stroke-width:1.5px
    classDef blocked fill:#FCE8E6,stroke:#B42318,color:#7A271A,stroke-width:1.5px

    class U,C,P,A,I,S,W,N process
    class R,V decision
    class D,X,B blocked

The diagram describes the intended secure request flow, including controls that still require verification. It should not be interpreted as proof that every gate is currently enforced.

Source components

Component Repository path Responsibility
Chat plugin chat/package/app/plugins/slack/plugin.py Tool definitions, intent routing, dispatch, response formatting
Tool registry chat/package/app/plugins/registry.py Tool registration, dispatch, permission checks
Permission policy chat/package/app/plugins/permissions.py Default tool-category permissions
OAuth and API routes integrations/package/app/handlers/integration_handlers.py OAuth callbacks, token resolution, Slack routes
Slack API client integrations/package/app/managers/slack_client.py Slack Web API requests and response handling
Alternate handlers integrations/package/app/handlers/slack_handlers.py Additional or legacy Slack operations; reachability requires verification
Settings integrations/package/app/settings.py Slack and service configuration

The chat plugin sends X-User-Id and X-Internal-Secret headers when a user ID is available. Every protected route must authenticate the internal caller, validate the user identity, and reject untrusted external requests.

4. OAuth and configuration

4.1 Configuration variables

Variable Purpose Handling requirement
SLACK_CLIENT_ID OAuth client identifier Configuration; not a password
SLACK_CLIENT_SECRET OAuth client secret Store in a secret manager or protected environment
SLACK_REDIRECT_URI Registered OAuth callback Must match the configured Slack app
SLACK_BOT_TOKEN Environment-configured bot token and current fallback credential Disable as an implicit fallback in per-user mode
SLACK_DEFAULT_CHANNEL Default channel setting Validate before use
SLACK_SIGNING_SECRET Slack request-signature verification setting Verify actual implementation before relying on it
JWT_SECRET_KEY Application JWT validation secret Keep secret; rotate under a controlled process
JWT_ALGORITHM Configured JWT validation algorithm Use an explicitly approved algorithm
INTERNAL_SECRET Internal service authentication secret Restrict access and rotate securely
FRONTEND_URL Frontend redirect destination Allowlist trusted destinations

The plugin's env_vars declaration lists SLACK_BOT_TOKEN and SLACK_DEFAULT_CHANNEL. OAuth initiation separately uses the Slack OAuth client settings.

Danger

Never commit real access tokens, refresh tokens, client secrets, signing secrets, JWT secrets, or internal-service secrets. Use placeholders in examples and redact credentials from logs, traces, and error responses.

4.2 Example environment configuration

The following is a template, not a complete deployment configuration.

# Slack OAuth
SLACK_CLIENT_ID=your_slack_client_id
SLACK_CLIENT_SECRET=replace_with_secret
SLACK_REDIRECT_URI=https://your-domain.example/integrations/slack/callback

# Optional environment-token mode.
# Do not use this as an implicit per-user fallback.
SLACK_BOT_TOKEN=

# Optional defaults
SLACK_DEFAULT_CHANNEL=

# Application security
JWT_SECRET_KEY=replace_with_secret
JWT_ALGORITHM=HS256
INTERNAL_SECRET=replace_with_internal_secret

# Frontend
FRONTEND_URL=https://your-domain.example

Do not copy placeholder values directly into production. Provision secrets through the deployment's approved secret-management mechanism.

4.3 OAuth flow

The handlers are implemented in integrations/package/app/handlers/integration_handlers.py.

sequenceDiagram
    autonumber
    actor U as User
    participant F as WhiteLotusAI frontend
    participant I as Integrations service
    participant S as Slack OAuth
    participant DB as Connection storage

    U->>F: Start Slack connection
    F->>I: Initiate OAuth
    I->>I: Validate application identity
    I->>DB: Store user-bound, single-use state
    I-->>F: Redirect to Slack authorization
    F->>S: Authorize requested scopes
    S-->>F: Redirect with code and state
    F->>I: OAuth callback
    I->>DB: Validate and consume state
    I->>S: Exchange authorization code
    S-->>I: OAuth response
    I->>DB: Store credentials for initiating user
    I-->>F: Redirect with connection result

The sequence illustrates the intended security properties. Verify the actual callback routing, state storage, and frontend redirect behavior against the implementation and tests.

The documented source flow is:

  1. The OAuth-start endpoint receives the application JWT in a query parameter.
  2. The handler validates the JWT and extracts the user ID.
  3. A random OAuth state is stored with the user ID.
  4. The browser is redirected to Slack's authorization endpoint.
  5. The callback validates and consumes the stored state.
  6. The authorization code is exchanged for a Slack OAuth response.
  7. Access-token and scope information are stored server-side.
  8. The user's Slack connection is marked active.
  9. The browser is redirected to the frontend with a connection result.

Warning

OAuth-start credential exposure: accepting an application JWT in a URL query parameter can expose it through browser history, proxy logs, monitoring, and URL-handling infrastructure. Review a safer authenticated initiation flow before production deployment.

Required OAuth safeguards:

  • Validate JWT signatures, expiry, and expected claims.
  • Generate unpredictable OAuth state values.
  • Bind state to the initiating user and consume it only once.
  • Apply state expiration and safe cleanup.
  • Validate the callback and redirect destination.
  • Store tokens server-side against the correct user and workspace.
  • Keep tokens out of frontend redirect URLs and application logs.
  • Verify that disconnecting a connection prevents further use of its credentials.

4.4 Requested OAuth scopes

The current authorization handler requests:

Scope Purpose Initial read-only release
channels:read Discover public channels Retain if required
channels:history Read public-channel history Retain if required
groups:read Discover accessible private channels Retain if required
groups:history Read accessible private-channel history Retain if required
chat:write Post messages Remove unless explicitly approved

Confirm the exact scope requirements against the Slack API methods and token type used by the implementation.

Important

Removing chat:write from the OAuth request is necessary for least privilege, but it is not sufficient by itself. The server-side tool policy and message-posting route must also deny write operations. Existing grants may need to be revoked or reauthorized, depending on the approved migration procedure.

The presence of SLACK_SIGNING_SECRET in configuration does not establish that inbound request-signature verification exists. If Slack events, commands, or webhooks are enabled, verify signature validation, timestamp freshness checks, and replay protection separately.

5. API operations

5.1 List channels

The Slack client calls conversations.list with:

Parameter Current behavior
exclude_archived true
limit 20
types public_channel,private_channel

Each returned channel includes its ID, name, and private-channel flag.

Known limitation: the current implementation does not paginate through all results. Do not describe channel discovery as exhaustive for larger workspaces.

Channel visibility depends on the Slack identity's granted permissions and accessible conversations. Listing a channel does not grant permission to read its history.

5.2 Retrieve channel history

The client calls conversations.history using the supplied channel identifier and requested limit.

The returned message fields include:

  • Message text.
  • Timestamp.
  • User ID.
Behavior Current implementation
Default result limit 10
Maximum server-side limit Not explicitly declared in the reviewed route
Full-history pagination Not implemented
Chat display limit At most 10 returned messages
Channel-name normalization Requires verification

The integrations route does not declare an explicit upper bound for the limit query parameter, and the client forwards the value to Slack. Add server-side validation before production use.

The tool description permits a channel name such as #general, but the client forwards the supplied value as Slack's channel parameter. Verify and normalize channel-name-to-ID behavior rather than assuming that names and IDs are interchangeable.

A recommended validation policy is:

DEFAULT_HISTORY_LIMIT = 10
MAX_HISTORY_LIMIT = 100  # Example policy; validate against provider limits.

def validate_history_limit(limit: int | None) -> int:
    if limit is None:
        return DEFAULT_HISTORY_LIMIT

    if limit < 1 or limit > MAX_HISTORY_LIMIT:
        raise ValueError("History limit is outside the permitted range")

    return limit

This is an illustrative validation pattern, not a claim that the repository already contains this function. Select the actual maximum based on provider constraints, application requirements, and tested behavior.

5.3 Post a message

The Slack client calls chat.postMessage with a channel and message body.

This is a state-changing operation and is outside the initial release scope.

The required policy is to reject the operation before invoking the integrations client or Slack API. Hiding the tool from the user interface or relying on conversational instructions is insufficient.

6. Critical finding: credential isolation

The _resolve_token helper in integrations/package/app/handlers/integration_handlers.py attempts to resolve a per-user Slack token when valid internal headers are available.

The reviewed behavior can fall back to SLACK_BOT_TOKEN when:

  • The user has not explicitly connected Slack.
  • A connection lookup fails.
  • A user-specific token cannot be retrieved.
  • Valid user and internal-secret headers are absent.

This is a significant authorization-design concern. A shared environment token may allow requests to operate under a common Slack identity rather than the initiating user's authorized connection.

Required remediation

  1. Fail closed in per-user mode. Missing connections and failed token lookups must reject the request.
  2. Remove implicit fallback. A failed per-user lookup must never silently switch to a shared token.
  3. Separate operating modes. If single-account environment-token mode is required, enable it explicitly with a documented trust boundary.
  4. Validate identity on every route. Never trust a caller-supplied user ID without authenticating the caller.
  5. Isolate caches. Cache keys must reflect the authenticated user and appropriate workspace or connection identity.
  6. Test cross-user access. Verify that one user cannot retrieve another user's data or unintentionally use a shared account.

Caution

Treat token fallback as a release-blocking issue for multi-user production until the behavior is corrected and authorization tests demonstrate isolation.

flowchart TD
    A["Incoming Slack request"] --> B{"Explicit operating mode?"}
    B -->|Per-user| C["Authenticate internal caller"]
    C --> D{"Valid user and active connection?"}
    D -->|Yes| E{"User token available?"}
    E -->|Yes| F["Use that user's token"]
    D -->|No| X["Reject request"]
    E -->|No| X

    B -->|Single-account| G{"Mode explicitly enabled?"}
    G -->|No| X
    G -->|Yes| H["Validate configured shared credential"]
    H --> I{"Credential valid?"}
    I -->|No| X
    I -->|Yes| J["Use shared identity under restricted policy"]

    classDef process fill:#E8F0FE,stroke:#315DA8,color:#172B4D,stroke-width:1.5px
    classDef decision fill:#FFF0CC,stroke:#9A6700,color:#513600,stroke-width:1.5px
    classDef safe fill:#DDF5E8,stroke:#238454,color:#12452D,stroke-width:1.5px
    classDef blocked fill:#FCE8E6,stroke:#B42318,color:#7A271A,stroke-width:1.5px

    class A,C,F,H,J process
    class B,D,E,G,I decision
    class X blocked

In shared-account mode, document that provider access occurs under the configured shared identity. Do not represent this mode as equivalent to per-user OAuth authorization.

7. Caching, errors, and rate limits

Area Observed behavior Required review
Channel-list cache TTL of 120 seconds Verify user and workspace isolation
Cache key Includes user ID when supplied, or env in environment-token mode Ensure the mode cannot be confused or bypassed
History cache Not present in the primary handler Reassess only if caching is introduced
HTTP timeout 10 seconds in the Slack client Test timeouts and cancellation
Provider errors Slack JSON ok field is checked Normalize failures safely
HTTP error mapping Many failures become HTTP 502 responses Avoid leaking internal details
Pagination Not implemented Document limits or implement pagination
Rate limiting Explicit Retry-After handling not implemented Add provider-aware throttling and retry behavior

Do not retry every failed request indiscriminately. Respect Slack's rate-limit responses, including Retry-After where applicable, and use bounded retries with backoff for operations that are safe to repeat.

Review error handling so provider responses, request details, access tokens, and internal exceptions are not exposed unnecessarily to callers.

8. Read-only security policy

The following controls are mandatory for the initial release.

Control Expected behavior
Tool allowlist Only approved read tools can be dispatched
Write-tool enforcement send_message is denied server-side
Message route POST /slack/message cannot perform a write in read-only mode
Internal authentication Protected routes reject unauthenticated external callers
User isolation Tokens and data remain bound to the authorized connection
Shared-token mode Disabled by default and explicitly configured if supported
Alternate handlers Every reachable handler follows the same security policy
Provider invocation Denied write operations never call chat.postMessage

The repository also contains integrations/package/app/handlers/slack_handlers.py. Verify whether these alternate handlers are registered or otherwise reachable. Any reachable route must enforce the same identity, credential-isolation, and read-only requirements.

READ_ONLY_SLACK_TOOLS = {
    "list_channels",
    "get_channel_history",
}

def is_slack_tool_allowed(tool_name: str, read_only: bool = True) -> bool:
    if read_only:
        return tool_name in READ_ONLY_SLACK_TOOLS

    # Non-read-only operation requires a separately approved policy.
    return False

This illustrates an explicit allowlist. It is not a drop-in replacement for the repository's authorization system; integrate the rule into the actual server-side dispatch and route enforcement layers.

9. Security and privacy requirements

Slack conversations may contain confidential business information, customer data, personal information, and operational details.

Apply the following safeguards:

  • Identity: authenticate the initiating user and validate the active Slack connection.
  • Least privilege: request only the scopes needed for approved read operations.
  • Authorization: verify access to the requested conversation through Slack and application policy.
  • Input validation: validate channel identifiers, result limits, and request payloads.
  • Credential protection: keep tokens and secrets out of logs, URLs, and error responses.
  • Cache isolation: separate cached results by the correct user and authentication mode.
  • Resilience: use bounded retries, timeouts, and provider-aware rate-limit handling.
  • Data minimization: return only the fields needed to answer the request.
  • Untrusted content: treat retrieved Slack messages as data, not as instructions that override system policy or authorization.
  • Read-only enforcement: prevent all unapproved state-changing operations.

10. Troubleshooting

Symptom Investigation
Slack cannot be connected Check OAuth client settings, callback URI, state handling, and Slack app installation
OAuth returns an error Inspect the provider response, code exchange, and granted scopes without logging credentials
Channel listing fails Verify the user's connection, token resolution, scopes, and channel access
A private channel is missing Confirm that the connected identity can access the channel
History returns no messages Verify the channel ID, required scope, channel membership, and requested limit
The wrong account or workspace is accessed Investigate shared-token fallback and per-user credential resolution immediately
Rate-limit errors occur Review provider limits, Retry-After, and bounded retry behavior
Slack requests time out Check integrations-service health, network access, and the HTTP timeout
A message is posted in read-only mode Treat as a release-blocking authorization defect
Cached channel data appears incorrect Inspect cache keys, TTL, connection status, and workspace association

Never troubleshoot OAuth by copying real tokens or secrets into source code, query strings, tickets, or documentation.

11. Testing checklist

Use these checklists as release acceptance criteria. Mark an item complete only after its behavior has been verified.

Functional tests

  • List channels in a connected workspace.
  • Retrieve recent messages from a permitted channel.
  • Handle empty channel lists and empty history results.
  • Validate channel identifiers and requested history limits.
  • Test channel names as input and verify normalization behavior.
  • Test workspaces with more than 20 channels and document pagination behavior.
  • Handle missing scopes, inaccessible channels, expired tokens, and revoked access.
  • Test rate limits, Retry-After, timeouts, and temporary outages.
  • Confirm that message contents and credentials are not unnecessarily logged.

Authorization tests

  • An unconnected user cannot access Slack in per-user mode.
  • One user cannot access another user's token or workspace data.
  • Connection lookup failures fail closed in per-user mode.
  • A shared-token fallback cannot bypass per-user authorization.
  • Only approved read tools are callable in the initial release.
  • send_message is rejected before provider invocation.
  • Direct requests to POST /slack/message cannot post in read-only mode.
  • Alternate handlers cannot bypass authentication or read-only controls.
  • Denied operations never invoke chat.postMessage.

OAuth tests

  • Invalid or expired application JWTs fail safely.
  • OAuth state is unpredictable, user-bound, single-use, and time-limited.
  • Tokens are stored against the correct user and workspace.
  • Access tokens are absent from redirect URLs and application logs.
  • Granted scopes match the approved release policy.
  • Disconnecting Slack prevents subsequent use of the connection.

Operational tests

  • Secrets are supplied through the approved configuration mechanism.
  • Cache keys separate users and authentication modes.
  • Provider errors do not expose sensitive internal details.
  • Retries are bounded and respect provider rate limits.
  • Logs and monitoring avoid unnecessary message-content retention.

12. Source references

File Review scope
chat/package/app/plugins/slack/plugin.py Registered tools, intent routing, dispatch, and response formatting
integrations/package/app/handlers/integration_handlers.py OAuth, token resolution, channel/history routes, and posting route
integrations/package/app/managers/slack_client.py Slack API calls, request limits, and timeout behavior
integrations/package/app/handlers/slack_handlers.py Alternate handlers and reachability
chat/package/app/plugins/registry.py Tool registration, dispatch, and permission checks
chat/package/app/plugins/permissions.py Default tool-category permissions
integrations/package/app/settings.py Slack and service configuration

13. Production readiness decision

Danger

Do not approve the Slack integration for multi-user production until the release-blocking security requirements are verified.

The reviewed implementation registers send_message, requests chat:write, exposes a message-posting route, and may fall back to a shared environment token.

Production approval requires evidence that:

  1. Read-only access is enforced at the tool and HTTP-route layers.
  2. Per-user credential resolution fails closed.
  3. OAuth scopes follow least privilege.
  4. OAuth state and token storage are correctly bound to the initiating user.
  5. Channel-history requests have validated, bounded limits.
  6. Internal routes and alternate handlers cannot bypass authorization.
  7. Cross-user isolation and denied-write tests pass.

Update this readiness decision only when the relevant code changes, tests, and deployment configuration have been reviewed.


Documentation scope: source-inspected implementation baseline. End-to-end behavior and production security remain subject to verification.