slackapi / bolt-python

A framework to build Slack apps using Python
https://slack.dev/bolt-python/
MIT License
1.03k stars 237 forks source link

How do I get the correct workspace team ID in message and mention handlers? #1107

Closed paulkuhle closed 1 week ago

paulkuhle commented 2 weeks ago

We have a Slack bot that is installed in several customer workspaces. Our bot can respond either to mentions using @app.event("app_mention") or to regular messages using @app.event("message"), depending on whether the customer has a separate channel for our bot or not.

In order to properly keep track of conversations and to verify customer's subscription details and so on, we need to reliably access the team ID of the workspace that the bot is running in. The main issues we've been facing are:

We currently don't have a way to reliably get the correct team ID, at least for the @app.event("app_mention") handler. Is there a different method or workaround?

Reproducible in:

@app.event("message")
async def handle_message(body, say, context, logger):
  logger.info(body)

@app.event("app_mention")
async def handle_app_mention_events(body, say, logger):
  logger.info(body)

The slack_bolt version

slack_bolt==1.19.0
slack_sdk==3.29.0
slackclient==2.9.4

Python runtime version

3.11.9

OS info

ProductName:        macOS
ProductVersion:     14.5
BuildVersion:       23F79
Darwin Kernel Version 23.5.0: Wed May  1 20:16:51 PDT 2024; root:xnu-10063.121.3~5/RELEASE_ARM64_T8103

Steps to reproduce:

Register a basic Slack bot with the message/mention handlers in a workspace setup such as the one described above (external users/external connections) and try to get the team ID of the workspace that the bot is running in, not the user's team ID.

Expected result:

Get the workspace's team ID.

Actual result:

Sometimes we can only get the team ID that the user belongs to, but not the team ID of the workspace that the bot belongs to.

Requirements

Please read the Contributing guidelines and Code of Conduct before creating this issue or pull request. By submitting, you are agreeing to those rules.

seratch commented 2 weeks ago

Hi @paulkuhle, thanks for asking the question!

The app_mention event payload is associated with a bot user, which belongs to a specific workspace. The event.team is always the one for the workspace the bot user is in. For context, when your app is installed into both sides of a Slack Connect channel, each workspace has its own bot user. If you invite both bot users into a Connect channel, your app can have two bots there, and there could be two different app_mention event patterns.

Nonetheless, in your case, I guess one of your customer workspaces added your app's bot user, and all members in the channel use that bot user regardless of which workspace they belong to.

Long story short, there are two patterns:

  1. If the human user who mentions the bot is in the same workspace, the team is the one for the user.
  2. If the human user who mentions the bot is in a different workspace, the app_mention payload can have event.user_team in addition to event.team.

I hope this clarifies things.

paulkuhle commented 1 week ago

Thank you for clarifying!

We're essentially just trying to reliably get the team ID of the workspace that the bot is installed in. Based on your explanation, event.team would be the right field for us when using the app_mention event handler.

What about the message app event? We're getting body.event.team, body.team_id and body.context_team_id. We've seen that the context_team_id and event.team fields can differ from the event.team field that an app_mention event in the same channel receives. Would team_id be the right field here?

seratch commented 1 week ago

When it comes to message events, it is unfortunately not that simple.

You can find authorizations and event_context in the event payload as shown below:

"authorizations": [
  {
    "enterprise_id": null,
    "team_id": "T03E94MJU",
    "user_id": "U06MGSUFUJY",
    "is_bot": true,
    "is_enterprise_install": false
  }
],
"event_context": "4-eyJldCI6Im1lc3NhZ2UiLCJ0aWQiOiJUMDNFOTRNSlUiLCJhaWQiOiJBMDZNVDNEQU4yViIsImNpZCI6IkNIRTJEVVc1ViJ9"

The authorizations property represents the active installations of your app, which are associated with this event delivery.

Although the authorizations is plural, the array property always contains only a single element (in the past, it had all the entries, but this was changed due to Slack's server-side capacity at some point). This means that when your app has several installations with the permissions required for this event delivery (i.e., scope and channel access), only one of them is included here.

If you can safely assume that only one bot user can exist in the Connect channel and that authorizations[0].is_bot in the payload is true, then authorization[0].team_id is the one you want to know.

If there is a possibility to have more than one bot user in the channel, you will need to check the rest of the active installations. To fetch all the authorizations, you can call apps.event.authorizations.list API with the event_context from the event payload and an app-level token (you can create this token with the authorizations:read scope on your https://api.slack.com/apps configuration page). Note that you may find more than one is_bot: true installation if several bot users are in the channel.

This is the essential way to identify the installed organization/workspace for Events API. If you want to consistently do the same, this works for the app_mention event and any other events too. Hope this makes sense to you.

paulkuhle commented 1 week ago

Thanks for the clarification!