slackapi / bolt-python

A framework to build Slack apps using Python

Home Page:https://slack.dev/bolt-python/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

MultiTeamsAuthorization Errors

manish001in opened this issue · comments

Hi Team,

I have been receiving these errors in my logs for a while now and I would like to figure out how to solve this.
I use my database Postgres through Sqlalchemy for installation and saving tokens. The installation is handled by a separate lambda service and this current service is used to handle events, actions and interaction with users.
In this service I use both bot tokens and user tokens to provide service to the end user.

I have tried finding the possible reasons for this issue but have been unable to do so. The app is used in multiple workspaces.

Happy to provide any more specific info if needed.

Reproducible in:

slack-bolt==1.18.0
slack-sdk==3.21.3
Python 3.11.2

Linux 6.1.34-59.116.amzn2023.aarch64 # 1 SMP Thu Jun 29 18:11:49 UTC 2023 aarch64 aarch64 aarch64 GNU/Linux

The slack_bolt version

slack-bolt==1.18.0

Python runtime version

Python 3.11.2

OS info

Linux 6.1.34-59.116.amzn2023.aarch64 # 1 SMP Thu Jun 29 18:11:49 UTC 2023 aarch64 aarch64 aarch64 GNU/Linux

Steps to reproduce:

N/A

Expected result:

No errors Ideally.

Actual result:


2024-02-11 02:03:24,642 app INFO As you've set SLACK_CLIENT_ID and SLACK_CLIENT_SECRET env variables, Bolt has enabled the file-based InstallationStore/OAuthStateStore for you. Note that these file-based stores are for local development. If you'd like to use a different data store, set the oauth_settings argument in the App constructor. Please refer to https://slack.dev/bolt-python/concepts#authenticating-oauth for more details.
2024-02-11 02:03:24,642 app WARNING As `installation_store` or `authorize` has been used, `token` (or SLACK_BOT_TOKEN env variable) will be ignored.
2024-02-11 02:03:24,737 slack_bolt.MultiTeamsAuthorization ERROR Although the app should be installed into this workspace, the AuthorizeResult (returned value from authorize) for it was not found.

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.

Hi @manish001in, thanks for asking the question!

Bolt has enabled the file-based InstallationStore/OAuthStateStore for you

As this log message says, currently your app is using the default local-file-system-based InstallationStore. If you're using SQLAlchemy, you can do similar with this example: https://github.com/slackapi/bolt-python/blob/main/examples/sqlalchemy/oauth_app.py

I hope this helps.

Hey @seratch , Thank you for the prompt response.

I am using the sqlalchemy methodology of oauth_app as mentioned in the shared link.
Please take a look at this code.

engine: Engine = sqlalchemy.create_engine(database_url)
installation_store = SQLAlchemyInstallationStore(
    client_id=client_id,
    engine=engine,
    logger=logger,
)
oauth_state_store = SQLAlchemyOAuthStateStore(
    expiration_seconds=120,
    engine=engine,
    logger=logger,
)

app = App(
    logger=logger,
    signing_secret=signing_secret,
    installation_store=installation_store,
    oauth_settings=OAuthSettings(
        client_id=client_id,
        client_secret=client_secret,
        state_store=oauth_state_store,
        scopes=(
            "app_mentions:read,bookmarks:read,channels:history,channels:read,"
            "chat:write,chat:write.customize,chat:write.public,commands,"
            "files:read,files:write,groups:history,groups:read,im:history,"
            "im:read,im:write,links:read,mpim:history,pins:read,team:read,"
            "usergroups:read,users:read,users:read.email,bookmarks:write,"
            "links.embed:write,mpim:write"
        ),
        user_scopes=(
            "bookmarks:read,channels:history,channels:read,files:read,"
            "groups:history,groups:read,im:history,im:read,links:read,"
            "mpim:history,mpim:read,stars:read,users:read,users:read.email,"
            "chat:write,im:write,mpim:write"
        ),
    ),
)


def create_auth_app():
    auth_app = App(
        logger=logger,
        signing_secret=signing_secret,
        token=app_token,
        url_verification_enabled=True,
        ignoring_self_events_enabled=True,
        request_verification_enabled=True,
    )
    return auth_app

As you can see, I do create another app in create_auth_app. This is used to call this API endpoint : auth_app.client.apps_event_authorizations_list along with event_context.

Could this be the cause of error here?
Any way I could solve this?
And would you say that the MultiTeamsAuthorization error is because of the issue with file based installation store situation??

Would love to understand more.

Thank you.

The auth_app needs to have the same installation_store and oauth_settings in its constructor arguments. Due to lack of them, auth_app is using the default file-based one.

Hey @seratch ,
Sorry if I am not understanding it correctly.

The auth_app used the app level token we generate for authorizations:read and then it is used to call this endpoint.
auth_app.client.apps_event_authorizations_list . How do I manage that?

If you just want to perform apps.event.authorizations.list API call with an app-level token, you don't need to initialize App instance for it. Instead, you can instantiate a WebClient instance and execute the API call: https://slack.dev/python-slack-sdk/web/index.html

If you're trying to execute apps.event.authorizations.list API call within a Slack event listener (e.g., app.event, app.action, app.view_submission etc.), installation_store is required to resolve the bot token for the workspace before running the listener. This is an opinionated design of the framework so that you have to follow it.

Hey @seratch ,
Sorry, I am still confused.

So this is the function using auth_app and apps.event.authorizations.list API call.
The basic app instantiation uses installation_store and I believe that gets resolved with the bot token for the workspace.
If I try to use the same app.client for apps.event.authorizations.list, I am unable to use that endpoint which is why I created the auth_app instance with the app level token.

I feel the issue could be that since I do not add the scope authorizations:read in the Oauthflow, my app instance doesn't have the required scope. Is that correct to think?
But then my concern becomes that I can't find any authorizations:read scope that I can add for bot/user level scopes in Oauth & Permissions tab and since it is an app level token, I do not know where do I ask for this scope in the Oauth flow.

Please help! Or if there is any example that I can learn from that would be great as well!

@app.event("message")
def handle_message(ack, body, say, logger):
    ack()

    try:
        current_users = get_current_slack_users()
        if "subtype" in body["event"] and body["event"]["subtype"] not in [
                "message_changed", "message_deleted",
                "message_replied", "thread_broadcast"]:
            return

        event_context = body["event_context"]
        team_id = body["team_id"]
        ts = body["event"]["ts"]
        channel = body["event"]["channel"]
        channel_type = body["event"]["channel_type"]
        channel_type = channel_types[channel_type]

        start_ts, end_ts = get_ts_values(ts)
        auth_list = []
        auth_app = create_auth_app()
        resp = auth_app.client.apps_event_authorizations_list(
            event_context=event_context,
        )

        if resp.get("ok"):
            auth_list = resp.get("authorizations", [])
            while resp.get("response_metadata", {}).get("next_cursor", ""):
                next_cursor = resp.get(
                    "response_metadata", {}).get("next_cursor", "")
                resp = auth_app.client.apps_event_authorizations_list(
                    event_context=event_context,
                    cursor=next_cursor,
                )

                auth_list = auth_list + resp.get("authorizations", [])
        else:
            logger.error(f"Error in App: Slack Authorization Error - {team_id}")

        if auth_list:
            for auth in auth_list:
                if auth["user_id"] in current_users:
                    user_channels = redis_connection.Set("{}_{}_{}-{}".format(
                        auth["user_id"], channel_type,
                        int(start_ts), int(end_ts)
                        ))

                    user_channels.add(channel)
                    user_channels.expire(2592000)

    except Exception as e:
        logger.error(
            f"Error in App: Event message handling \
error - {e}\n{traceback.format_exc()}")

As mentioned in the API document, the endpoint requires an "app-level" token, which can be issued per app, not per workspace/org. You can create a new app-level token at Settings > Basic Information > App-Level Tokens (https://api.slack.com/apps) with the scope. This means that your app can have a universal app-level token for the apps.event.authorizations.list API calls while it also has bot/user tokens per workspace. In your code, you can instantiate a singleton WebClient with the app-level token and use it within listeners. Does this make sense?

Hey @seratch. Thanks a lot for the help!
I used a WebClient singleton with my token and that resolved the issue of installation_store etc.

However, I am still encountering this error

2024-03-12 00:46:06,159 slack_bolt.MultiTeamsAuthorization ERROR Although the app should be installed into this workspace, the AuthorizeResult (returned value from authorize) for it was not found.
2024-03-12 00:46:11,641 slack_bolt.MultiTeamsAuthorization ERROR Although the app should be installed into this workspace, the AuthorizeResult (returned value from authorize) for it was not found.

Would appreciate some help here as well!

Thank you!

I mean the SQLAlchemy installation_store that is connected to your database is still required to resolve bot/user tokens. If you're using SQLAlchemy one but receiving the error, it should mean that your database does not have the installation data for some reason. Re-installing the app through the OAuth flow using the SQLAlchemy installation_store can resolve it.

Thank you @seratch. Appreciate all your help! I will try to get this checked and ensure if it works.