slackapi / bolt-python

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

How does `bolt-python` rotate tokens? #1084

Closed kennym closed 1 day ago

kennym commented 1 month ago

We enabled Token Rotation for our Slack app, however I was unsure of:

  1. How does slack-bolt rotate our bot token exactly? Does it schedule a task to update the bot_token before the bot_token_expires_at time, or do we have to make sure we schedule that?
  2. Today I tested the token rotation, and it did not seem to update the bot_token using the example Django approach.
image

image

Reproducible in:

django-slack==5.19.0
slack-bolt==1.18.1
slack-sdk==3.26.1
Python 3.11.6
ProductName:            macOS
ProductVersion:         14.4.1
BuildVersion:           23E224
Darwin Kernel Version 23.4.0: Fri Mar 15 00:10:42 PDT 2024; root:xnu-10063.101.17~1/RELEASE_ARM64_T6000
zimeg commented 1 month ago

Hey @kennym! 👋 Thanks for exploring token rotation and writing in!

How does slack-bolt rotate our bot token exactly? Does it schedule a task to update the bot_token before the bot_token_expires_at time, or do we have to make sure we schedule that?

A check to rotate tokens happens with each request and rotations are done when needed. This should all happen behind the scenes if you're using the built-in OAuth functionality too 🤔

Today I tested the token rotation, and it did not seem to update the bot_token using the example Django approach.

Ah darn... I'm not immediately sure why this might be. Do you happen to be using the oauth_app/slack_listeners.py version of the app? Perhaps the suggested token_rotation_expiration_minutes=1000000 is preventing token rotation from happening after 12 hours.

From the docs:

Notice that your access_token now ... will always expire in 43,200 seconds, which is 12 hours.

Reducing this time to <=720 might be a fix and can be helpful for testing. I hope this is helpful, but I'm interested if this is the case for your setup or if it might be something else. Please let me know!

kennym commented 1 month ago

Thank you, your answer is very appreciated.

A check to rotate tokens happens with each request and rotations are done when needed. This should all happen behind the scenes if you're using the built-in OAuth functionality too 🤔

Thanks for all the references. This makes a lot more sense now.

I will test again.

Reducing this time to <=720 might be a fix and can be helpful for testing. I hope this is helpful, but I'm interested if this is the case for your setup or if it might be something else. Please let me know!

How low can we go here?

seratch commented 1 month ago

The bot_token_expires_at time is not customizable as Slack server-side decides the value and includes it in the API response.

While I understand the option name "token_rotation_expiration_minutes" is a bit confusing, you can set token_rotation_expiration_minutes=1000000 to let bolt-python do rotation every time you receive a request from Slack. (see also: https://github.com/slackapi/bolt-python/issues/510#issuecomment-958693339) If you don't customize the value, bolt-python does rotation either when the token is expiring within 120 minutes or when the token is already expired when it receives a request from Slack.

kennym commented 1 month ago

or when the token is already expired when it receives a request from Slack.

So, the Token Rotation will still work with the refresh token even after the bot_token has expired?

Which would effectively mean that as long as we have SlackInstallation and SlackBot records we should not run into errors with expired tokens, correct?

While I understand the option name "token_rotation_expiration_minutes" is a bit confusing

Indeed it was confusing, but now it makes perfect sense. Can I suggested updating the documentation here to specify that? https://slack.dev/bolt-python/api-docs/slack_bolt/oauth/oauth_settings.html#slack_bolt.oauth.oauth_settings.OAuthSettings.token_rotation_expiration_minutes

kennym commented 1 month ago

While I understand the option name "token_rotation_expiration_minutes" is a bit confusing, you can set token_rotation_expiration_minutes=1000000 to let bolt-python do rotation every time you receive a request from Slack. (see also: https://github.com/slackapi/bolt-python/issues/510#issuecomment-958693339) If you don't customize the value, bolt-python does rotation either when the token is expiring within 120 minutes or when the token is already expired when it receives a request from Slack.

For testing I've set token_rotation_expiration_minutes=1000000, but I'm not seeing our tokens being rotated.

For context, we're using the Slack Events API (webhooks).

We handle a request from the Events API, route it through our system, where we eventually send a message back to the user, like so:

  OAUTH_SETTINGS = OAuthSettings(
      success_url=success_url,
      install_page_rendering_enabled=False,
      install_path="/api/oauth/slack/install/",
      redirect_uri_path="/api/oauth/slack/oauth_redirect/",
      client_id=client_id,
      client_secret=client_secret,
      scopes=scopes,
      user_scopes=user_scopes,
      # token_rotation_expiration_minutes=FIVE_DAYS_IN_MINUTES,
      token_rotation_expiration_minutes=1000000,
      installation_store=DjangoInstallationStore(
          client_id=client_id,
          logger=log,
      ),
      state_store=DjangoOAuthStateStore(
          expiration_seconds=120,
          logger=log,
      ),
  )

    slack_app = SlackApp(
        token=bot_token,
        signing_secret=settings.SLACK_SIGNING_SECRET,
        oauth_settings=OAUTH_SETTINGS,
    )

    slack_app.client.chat_postMessage(...)

However this doesn't seem to trigger the token rotation.

Both the SlackInstallation.bot_token and SlackBot.bot_token stay the same.

What am I doing wrong?

seratch commented 1 month ago

The automatic rotation can be triggered only when your app's listeners (e.g., app.event, app.action) are executed. If you need to use WebClient outside of such functions, you can manually run the same rotation logic before utilizing the stored tokens. Please refer to the following internal code in bolt-python to learn how to implement this:

github-actions[bot] commented 2 weeks ago

👋 It looks like this issue has been open for 30 days with no activity. We'll mark this as stale for now, and wait 10 days for an update or for further comment before closing this issue out. If you think this issue needs to be prioritized, please comment to get the thread going again! Maintainers also review issues marked as stale on a regular basis and comment or adjust status if the issue needs to be reprioritized.

github-actions[bot] commented 1 day ago

As this issue has been inactive for more than one month, we will be closing it. Thank you to all the participants! If you would like to raise a related issue, please create a new issue which includes your specific details and references this issue number.