11from logging import Logger
2- from typing import Optional , Callable , Awaitable , Dict , Any
2+ from typing import Optional , Callable , Awaitable , Dict , Any , List
33
44from slack_sdk .errors import SlackApiError
55from slack_sdk .oauth .installation_store import Bot , Installation
@@ -156,14 +156,18 @@ async def __call__(
156156
157157 bot_token : Optional [str ] = None
158158 user_token : Optional [str ] = None
159+ bot_scopes : Optional [List [str ]] = None
160+ user_scopes : Optional [List [str ]] = None
161+ latest_bot_installation : Optional [Installation ] = None
162+ this_user_installation : Optional [Installation ] = None
159163
160164 if not self .bot_only and self .find_installation_available :
161165 # Since v1.1, this is the default way.
162166 # If you want to use find_bot / delete_bot only, you can set bot_only as True.
163167 try :
164168 # Note that this is the latest information for the org/workspace.
165169 # The installer may not be the user associated with this incoming request.
166- latest_installation : Optional [ Installation ] = await self .installation_store .async_find_installation (
170+ latest_bot_installation = await self .installation_store .async_find_installation (
167171 enterprise_id = enterprise_id ,
168172 team_id = team_id ,
169173 is_enterprise_install = context .is_enterprise_install ,
@@ -173,20 +177,20 @@ async def __call__(
173177 # The example use cases are:
174178 # - The app's installation requires both bot and user tokens
175179 # - The app has two installation paths 1) bot installation 2) individual user authorization
176- this_user_installation : Optional [Installation ] = None
177-
178- if latest_installation is not None :
180+ if latest_bot_installation is not None :
179181 # Save the latest bot token
180- bot_token = latest_installation .bot_token # this still can be None
181- user_token = latest_installation .user_token # this still can be None
182+ bot_token = latest_bot_installation .bot_token # this still can be None
183+ user_token = latest_bot_installation .user_token # this still can be None
184+ bot_scopes = latest_bot_installation .bot_scopes # this still can be None
185+ user_scopes = latest_bot_installation .user_scopes # this still can be None
182186
183- if latest_installation .user_id != user_id :
187+ if latest_bot_installation .user_id != user_id :
184188 # First off, remove the user token as the installer is a different user
185189 user_token = None
186- latest_installation .user_token = None
187- latest_installation .user_refresh_token = None
188- latest_installation .user_token_expires_at = None
189- latest_installation .user_scopes = []
190+ latest_bot_installation .user_token = None
191+ latest_bot_installation .user_refresh_token = None
192+ latest_bot_installation .user_token_expires_at = None
193+ latest_bot_installation .user_scopes = []
190194
191195 # try to fetch the request user's installation
192196 # to reflect the user's access token if exists
@@ -198,26 +202,32 @@ async def __call__(
198202 )
199203 if this_user_installation is not None :
200204 user_token = this_user_installation .user_token
201- if latest_installation .bot_token is None :
205+ user_scopes = this_user_installation .user_scopes
206+ if latest_bot_installation .bot_token is None :
202207 # If latest_installation has a bot token, we never overwrite the value
203208 bot_token = this_user_installation .bot_token
209+ bot_scopes = this_user_installation .bot_scopes
204210
205211 # If token rotation is enabled, running rotation may be needed here
206212 refreshed = await self ._rotate_and_save_tokens_if_necessary (this_user_installation )
207213 if refreshed is not None :
208214 user_token = refreshed .user_token
209- if latest_installation .bot_token is None :
215+ user_scopes = refreshed .user_scopes
216+ if latest_bot_installation .bot_token is None :
210217 # If latest_installation has a bot token, we never overwrite the value
211218 bot_token = refreshed .bot_token
219+ bot_scopes = refreshed .bot_scopes
212220
213221 # If token rotation is enabled, running rotation may be needed here
214- refreshed = await self ._rotate_and_save_tokens_if_necessary (latest_installation )
222+ refreshed = await self ._rotate_and_save_tokens_if_necessary (latest_bot_installation )
215223 if refreshed is not None :
216224 bot_token = refreshed .bot_token
225+ bot_scopes = refreshed .bot_scopes
217226 if this_user_installation is None :
218227 # Only when we don't have `this_user_installation` here,
219228 # the `user_token` is for the user associated with this request
220229 user_token = refreshed .user_token
230+ user_scopes = refreshed .user_scopes
221231
222232 except NotImplementedError as _ :
223233 self .find_installation_available = False
@@ -238,6 +248,7 @@ async def __call__(
238248 )
239249 if bot is not None :
240250 bot_token = bot .bot_token
251+ bot_scopes = bot .bot_scopes
241252 if bot .bot_refresh_token is not None :
242253 # Token rotation
243254 if self .token_rotator is None :
@@ -249,6 +260,7 @@ async def __call__(
249260 if refreshed is not None :
250261 await self .installation_store .async_save_bot (refreshed )
251262 bot_token = refreshed .bot_token
263+ bot_scopes = refreshed .bot_scopes
252264
253265 except NotImplementedError as _ :
254266 self .find_bot_available = False
@@ -267,10 +279,16 @@ async def __call__(
267279
268280 try :
269281 auth_test_api_response = await context .client .auth_test (token = token )
282+ user_auth_test_response = None
283+ if user_token is not None and token != user_token :
284+ user_auth_test_response = await context .client .auth_test (token = user_token )
270285 authorize_result = AuthorizeResult .from_auth_test_response (
271286 auth_test_response = auth_test_api_response ,
287+ user_auth_test_response = user_auth_test_response ,
272288 bot_token = bot_token ,
273289 user_token = user_token ,
290+ bot_scopes = bot_scopes ,
291+ user_scopes = user_scopes ,
274292 )
275293 if self .cache_enabled :
276294 self .authorize_result_cache [token ] = authorize_result
0 commit comments