diff --git a/slack_bolt/oauth/async_oauth_flow.py b/slack_bolt/oauth/async_oauth_flow.py index e7f0fa724..6ce98cb3c 100644 --- a/slack_bolt/oauth/async_oauth_flow.py +++ b/slack_bolt/oauth/async_oauth_flow.py @@ -331,8 +331,8 @@ async def run_installation(self, code: str) -> Optional[Installation]: if bot_token is not None: auth_test = await self.client.auth_test(token=bot_token) bot_id = auth_test["bot_id"] - if is_enterprise_install is True: - enterprise_url = auth_test.get("url") + if is_enterprise_install is True: + enterprise_url = auth_test.get("url") return Installation( app_id=oauth_response.get("app_id"), diff --git a/tests/slack_bolt/oauth/test_oauth_flow.py b/tests/slack_bolt/oauth/test_oauth_flow.py index 77258685d..00d1dceba 100644 --- a/tests/slack_bolt/oauth/test_oauth_flow.py +++ b/tests/slack_bolt/oauth/test_oauth_flow.py @@ -287,3 +287,36 @@ def failure(args: FailureArgs) -> BoltResponse: resp = oauth_flow.handle_callback(req) assert resp.status == 502 assert resp.body == "customized" + + def test_run_installation_org_wide_install_without_bot_token(self): + # An org-wide install of an app that only asks for user scopes + # returns no access_token, so auth.test must not be called + oauth_flow = OAuthFlow( + client=WebClient(base_url=self.mock_api_server_base_url), + settings=OAuthSettings( + client_id="111.222", + client_secret="xxx", + scopes=["chat:write", "commands"], + installation_store=FileInstallationStore(), + state_store=FileOAuthStateStore(expiration_seconds=120), + ), + ) + + def oauth_v2_access(**kwargs): + return { + "ok": True, + "app_id": "A111", + "is_enterprise_install": True, + "enterprise": {"id": "E111", "name": "Org"}, + "team": None, + "authed_user": {"id": "U111", "scope": "search:read", "access_token": "xoxp-1234", "token_type": "user"}, + } + + oauth_flow.client.oauth_v2_access = oauth_v2_access + + installation = oauth_flow.run_installation("code") + assert installation is not None + assert installation.is_enterprise_install is True + assert installation.enterprise_id == "E111" + assert installation.bot_token is None + assert installation.user_token == "xoxp-1234" diff --git a/tests/slack_bolt_async/oauth/test_async_oauth_flow.py b/tests/slack_bolt_async/oauth/test_async_oauth_flow.py index 538861c05..a3e27b9d7 100644 --- a/tests/slack_bolt_async/oauth/test_async_oauth_flow.py +++ b/tests/slack_bolt_async/oauth/test_async_oauth_flow.py @@ -334,3 +334,37 @@ async def failure(args: AsyncFailureArgs) -> BoltResponse: resp = await oauth_flow.handle_callback(req) assert resp.status == 502 assert resp.body == "customized" + + @pytest.mark.asyncio + async def test_run_installation_org_wide_install_without_bot_token(self): + # An org-wide install of an app that only asks for user scopes + # returns no access_token, so auth.test must not be called + oauth_flow = AsyncOAuthFlow( + client=AsyncWebClient(base_url=self.mock_api_server_base_url), + settings=AsyncOAuthSettings( + client_id="111.222", + client_secret="xxx", + scopes=["chat:write", "commands"], + installation_store=FileInstallationStore(), + state_store=FileOAuthStateStore(expiration_seconds=120), + ), + ) + + async def oauth_v2_access(**kwargs): + return { + "ok": True, + "app_id": "A111", + "is_enterprise_install": True, + "enterprise": {"id": "E111", "name": "Org"}, + "team": None, + "authed_user": {"id": "U111", "scope": "search:read", "access_token": "xoxp-1234", "token_type": "user"}, + } + + oauth_flow.client.oauth_v2_access = oauth_v2_access + + installation = await oauth_flow.run_installation("code") + assert installation is not None + assert installation.is_enterprise_install is True + assert installation.enterprise_id == "E111" + assert installation.bot_token is None + assert installation.user_token == "xoxp-1234"