Repository navigation
Correct Authorization Flow for Workspace Bot *and then* generate User tokens later #574
Description
Activity
- addedquestionFurther information is requestedFurther information is requested
on Jan 14, 2022 Hi @stantonius, thanks for asking the question! Also, we're glad to hear that you like bolt-python!
App is installed to entire workspace. Bot token is generated and embedded in the Bolt code
As your app implements the OAuth for app installations, your installation data is managed in the
InstallationStore(in your example code, it's local file system basedFileInstallationStore). Thus, you don't need to pass thetokenargument to yourAppinitialization. Bolt automatically resolves relevant bot tokens for each incoming request from Slack.Also, if you use the installation from the Slack app admin page, the generated token does not work in this way. As your app offers the OAuth flow, all the installations must be done from the
/slack/installendpoint.user scopes
You are passing
"users:read", "users:read.email"as both bot scopes and user scopes to the OAuth authorize URL. However, if you need only these scopes, having them in bot scopes would be enough. Also, forapp_home_openedevents andviews.publishAPI call, you don't need any user scopes.I hope this helps!
Hey @seratch thanks for getting back to me so quickly.
Thus, you don't need to pass the token argument to your App initialization.
Makes sense.
However, if you need only these scopes, having them in bot scopes would be enough. Also, for app_home_opened events and views.publish API call, you don't need any user scopes.
Agreed. Sorry I should have been more explicit - the code I shared was a sample and I had removed some of the Scopes for readability. But this validates my understanding.
generated token does not work in this way. As your app offers the OAuth flow, all the installations must be done from the /slack/install endpoint.
OK so this is where my issue is then. Are you aware of any way to have this integrated approach, where the Bot is available to the workspace and offers this Install button as part of its chat or on its Home page? Otherwise I would need to either:
- Have 2 Apps (one for this initial UI that is immediately available to all workspace users, the second appears when each user installs via the
/slack/installendpoint). Not ideal as these are really the same Apps - Distribute the URL by some other mechanism. Also not ideal as I assume this will have lower engagement
Thanks again for your help with this
- Have 2 Apps (one for this initial UI that is immediately available to all workspace users, the second appears when each user installs via the
@stantonius
I may not fully understand what you want to do here but if you mean you need two OAuth installation flows for 1) enabling your app in the workspace (=bot installation) and 2) individual user installation with user scopes, I would suggest:- Create two
Appinstances with the same set of client_id/client_secret- 1:
Appwith theoauth_settingsfor bot installation (with bot scopes) - 2:
Appwith theoauth_settingsfor user scope installation (with user scopes)
- 1:
- Have two sets of installation endpoints
- 1:
/slack/app_installand/slack/app_oauth_redirect - 2:
/slack/user_installand/slack/user_oauth_redirectand use correspondingAppinstance for each
- 1:
- Share a single
InstallationStoreamong them - As long as
InstallationStoremanages all installations, either of 1: or 2: can serve/slack/events. If you want to have a differentAppfor/slack/events, it's also fine. - If you want to receive a user token associated with the incoming request, a token can be available as
context.user_tokenas long as the user already installed the app via 2) OAuth flow see alsoauthorizeusingInstallationStoreunder the hood
If you are fine to have two Slack apps, of course, things can be much simpler. You can run those apps either in different processes or in different sets of FastAPI endpoints. Either way, having two
Appinstances would be the same.Does this make sense to you?
- Create two
@stantonius Let us know if you have more to ask/discuss here 👋 We'll close this issue after waiting for your response for a few more days.
Apologies for the delay and thanks for following up - this team is on it!
The sharing of client ids and installations was an awesome idea. I think I have this working as you mentioned, however I'm still working through a few details when I have time.
For what it is worth, what really tripped me up (which you rightfully mentioned in your response) was that the tokens generated in the App admin portal cannot be referenced in your Bolt code if you are also using Oauth unless you write your own authorization flow for each request - which defeats some of the purpose of using Bolt. I hadn't understood that tokens generated in the admin page do not update in your app's installation yet tokens generated via Oauth do flow back to Slack and are reflected in the admin page. Basically if using Oauth and installations in your app, do not generate the tokens in the admin page - go to the
/slack/installendpoint and install this way, and the tokens will still appear in the admin page but also in the installation.It was the above misunderstanding that caused this
MultiTeamsAuthorization/AuthorizeResulterror - even when I provided legit tokens generated from the admin portal directly to theAppinstance, it was ignored and only looked via the defaultauthorizefunction.Finally, I did notice some of the feedback to your PR was that this was a complicated workflow/scenario. I had made some additional notes on what I was trying to do in case it was helpful as to why all this was necessary.
The app I am building requires a few scopes be accessible by user_token for additional functionality - I am trying to create a single app that fits the following criteria:
- The App is installed at the workspace level and is immediately available to everyone in the workspace
- Each individual user is then presented with the option to enable the features that require more access than a workspace bot is allowed.
The rationale for this workflow is to me a good mix of maximizing App engagement (already pre-installed and visible, can nudge and provide more context) while being transparent on permissions and giving the end user full control (progressive permission flow started by the organization, left with the users to ultimately decide on any privileged access) - all within a single app package.
Thanks for all your hard work
Thanks for your reply!
the token generated via admin page installation vs the OAuth flow
Yes, we have been observing that this difference is one of the confusing points for new Slack app developers. Glad to know you've figured it out but, in the future, our team may be able to improve the documents to help new developers more easily understand this.
the scenario you mentioned in the comment
The pull request #576 should resolve one blocker for your use case. Please try the latest version out. If you have anything further to ask/clarify in your app development, please feel free to open a new question issue.
It seems that there is nothing else we can offer here. Let us close this issue now. Thanks again for your time to write in here!
First of all, loving the Slack Bolt dev experience. And really appreciate the community and responsiveness from maintainers.
I have put this as a question because I'm pretty sure I am missing a fundamental Oauth step here - I just can't figure it out.
As described in the Expected Result section below, I am trying to create an App that is both a Bot and also uses the Web API that requires user_tokens. The Bot and Home page are meant to be present regardless of whether the user has a user_token stored or not - the Home Page UI and Bot responses will just depend on whether the user_token exists. While I have the whole setup working, the flow is really choppy. I can create the App for the workspace, however when a user then goes to interact with the App (either via the Home page or the Bot), the Bolt App returns the error
slack_bolt.MultiTeamsAuthorization:Although the app should be installed into this workspace, the AuthorizeResult (returned value from authorize) for it was not found.Note that if the user first goes to the
/slack/installroute from a browser, the user_tokens are generated and if you allow Slack to be opened, the permissions are recognised and the user can interact with the App's advanced functionality that requires the user_tokensI know from the Bolt docs that apps that span multiple workspaces may require an
authorizefunction, however I had never selected or implied that this was a multi-workspace app, so I am unsure why the App is expecting anAuthorizeResultreturned.I also know there have been similar questions asked before, however what I am experiencing is that this error is introduced before any of the event callbacks are triggered. Ie. I can't do any of my own validation on the "app_home_opened" event callback as this is never triggered, and thus I don't have access to the
clientobject unless I recreate one somehow. As you can see in the screenshot below, the only object I have access to currently (without the customauthorizefunction) is the initial Request json. Even the Oauth_flow callbacks are not triggered (where I could also set some custom logic), which suggests thisMultiTeamsAuthorizationerror occurs before the Oauth_flow is validated.Is my only solution for this to create a custom
authorizefunction to handle all of the permission checks each time? This is not ideal as one of the advantages of using Bolt is that it handles the Oauth protocol and token verification for us, which I would like to avoid writing myself (and possibly introducing security vulnerabilities)Many thanks for any guidance available
Reproducible in:
uvicorn main:api --reload --port 3000 --log-level warningThe
slack_boltversionslack-bolt==1.11.1
slack-sdk==3.13.0
Note that FastAPI adapter is used
Python runtime version
3.9.9
OS info
ProductName: macOS
ProductVersion: 12.0.1
BuildVersion: 21A559
Steps to reproduce:
See below
Expected result:
Actual result:
slack_bolt.MultiTeamsAuthorization:Although the app should be installed into this workspace, the AuthorizeResult (returned value from authorize) for it was not found.The Home page never loads and the Bot is not functional.