Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 21 additions & 10 deletions slack_bolt/oauth/async_oauth_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,19 +162,30 @@ def sqlite3(
async def handle_installation(self, request: AsyncBoltRequest) -> BoltResponse:
state = await self.issue_new_state(request)
url = await self.build_authorize_url(state, request)
html = await self.build_install_page_html(url, request)
set_cookie_value = self.settings.state_utils.build_set_cookie_for_new_state(
state
)
return BoltResponse(
status=200,
body=html,
headers={
"Content-Type": "text/html; charset=utf-8",
"Content-Length": len(bytes(html, "utf-8")),
"Set-Cookie": [set_cookie_value],
},
)
if self.settings.install_page_rendering_enabled:
html = await self.build_install_page_html(url, request)
return BoltResponse(
status=200,
body=html,
headers={
"Content-Type": "text/html; charset=utf-8",
"Content-Length": len(bytes(html, "utf-8")),
"Set-Cookie": [set_cookie_value],
},
)
else:
return BoltResponse(
status=302,
body="",
headers={
"Content-Type": "text/html; charset=utf-8",
"Location": url,
"Set-Cookie": [set_cookie_value],
},
)

# ----------------------
# Internal methods for Installation
Expand Down
4 changes: 4 additions & 0 deletions slack_bolt/oauth/async_oauth_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class AsyncOAuthSettings:
redirect_uri: Optional[str]
# Handler configuration
install_path: str
install_page_rendering_enabled: bool
redirect_uri_path: str
callback_options: Optional[CallbackOptions] = None
success_url: Optional[str]
Expand Down Expand Up @@ -63,6 +64,7 @@ def __init__(
redirect_uri: Optional[str] = None,
# Handler configuration
install_path: str = "/slack/install",
install_page_rendering_enabled: bool = True,
redirect_uri_path: str = "/slack/oauth_redirect",
callback_options: Optional[CallbackOptions] = None,
success_url: Optional[str] = None,
Expand All @@ -86,6 +88,7 @@ def __init__(
:param user_scopes: Check the value in Settings > Manage Distribution
:param redirect_uri: Check the value in Features > OAuth & Permissions > Redirect URLs
:param install_path: The endpoint to start an OAuth flow (Default: /slack/install)
:param install_page_rendering_enabled: Renders a web page for install_path access if True
:param redirect_uri_path: The path of Redirect URL (Default: /slack/oauth_redirect)
:param callback_options: Give success/failure functions f you want to customize callback functions.
:param success_url: Set a complete URL if you want to redirect end-users when an installation completes.
Expand Down Expand Up @@ -119,6 +122,7 @@ def __init__(
self.install_path = install_path or os.environ.get(
"SLACK_INSTALL_PATH", "/slack/install"
)
self.install_page_rendering_enabled = install_page_rendering_enabled
self.redirect_uri_path = redirect_uri_path or os.environ.get(
"SLACK_REDIRECT_URI_PATH", "/slack/oauth_redirect"
)
Expand Down
31 changes: 21 additions & 10 deletions slack_bolt/oauth/oauth_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,19 +157,30 @@ def sqlite3(
def handle_installation(self, request: BoltRequest) -> BoltResponse:
state = self.issue_new_state(request)
url = self.build_authorize_url(state, request)
html = self.build_install_page_html(url, request)
set_cookie_value = self.settings.state_utils.build_set_cookie_for_new_state(
state
)
return BoltResponse(
status=200,
body=html,
headers={
"Content-Type": "text/html; charset=utf-8",
"Content-Length": len(bytes(html, "utf-8")),
"Set-Cookie": [set_cookie_value],
},
)
if self.settings.install_page_rendering_enabled:
html = self.build_install_page_html(url, request)
return BoltResponse(
status=200,
body=html,
headers={
"Content-Type": "text/html; charset=utf-8",
"Content-Length": len(bytes(html, "utf-8")),
"Set-Cookie": [set_cookie_value],
},
)
else:
return BoltResponse(
status=302,
body="",
headers={
"Content-Type": "text/html; charset=utf-8",
"Location": url,
"Set-Cookie": [set_cookie_value],
},
)

# ----------------------
# Internal methods for Installation
Expand Down
4 changes: 4 additions & 0 deletions slack_bolt/oauth/oauth_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class OAuthSettings:
redirect_uri: Optional[str]
# Handler configuration
install_path: str
install_page_rendering_enabled: bool
redirect_uri_path: str
callback_options: Optional[CallbackOptions] = None
success_url: Optional[str]
Expand Down Expand Up @@ -58,6 +59,7 @@ def __init__(
redirect_uri: Optional[str] = None,
# Handler configuration
install_path: str = "/slack/install",
install_page_rendering_enabled: bool = True,
redirect_uri_path: str = "/slack/oauth_redirect",
callback_options: Optional[CallbackOptions] = None,
success_url: Optional[str] = None,
Expand All @@ -81,6 +83,7 @@ def __init__(
:param user_scopes: Check the value in Settings > Manage Distribution
:param redirect_uri: Check the value in Features > OAuth & Permissions > Redirect URLs
:param install_path: The endpoint to start an OAuth flow (Default: /slack/install)
:param install_page_rendering_enabled: Renders a web page for install_path access if True
:param redirect_uri_path: The path of Redirect URL (Default: /slack/oauth_redirect)
:param callback_options: Give success/failure functions f you want to customize callback functions.
:param success_url: Set a complete URL if you want to redirect end-users when an installation completes.
Expand Down Expand Up @@ -113,6 +116,7 @@ def __init__(
self.install_path = install_path or os.environ.get(
"SLACK_INSTALL_PATH", "/slack/install"
)
self.install_page_rendering_enabled = install_page_rendering_enabled
self.redirect_uri_path = redirect_uri_path or os.environ.get(
"SLACK_REDIRECT_URI_PATH", "/slack/oauth_redirect"
)
Expand Down
22 changes: 21 additions & 1 deletion tests/slack_bolt/oauth/test_oauth_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def test_instantiation(self):
assert oauth_flow.logger is not None
assert oauth_flow.client is not None

def test_handle_installation(self):
def test_handle_installation_default(self):
oauth_flow = OAuthFlow(
settings=OAuthSettings(
client_id="111.222",
Expand All @@ -58,6 +58,26 @@ def test_handle_installation(self):
assert resp.headers.get("content-length") == ["576"]
assert "https://slack.com/oauth/v2/authorize?state=" in resp.body

# https://github.com/slackapi/bolt-python/issues/183
# For direct install URL suppport
def test_handle_installation_no_rendering(self):
oauth_flow = OAuthFlow(
settings=OAuthSettings(
client_id="111.222",
client_secret="xxx",
scopes=["chat:write", "commands"],
user_scopes=["search:read"],
installation_store=FileInstallationStore(),
install_page_rendering_enabled=False, # disabled
state_store=FileOAuthStateStore(expiration_seconds=120),
)
)
req = BoltRequest(body="")
resp = oauth_flow.handle_installation(req)
assert resp.status == 302
location_header = resp.headers.get("location")[0]
assert "https://slack.com/oauth/v2/authorize?state=" in location_header

def test_scopes_as_str(self):
settings = OAuthSettings(
client_id="111.222",
Expand Down
20 changes: 19 additions & 1 deletion tests/slack_bolt_async/oauth/test_async_oauth_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ async def test_instantiation_non_async_settings_to_app(self):
)

@pytest.mark.asyncio
async def test_handle_installation(self):
async def test_handle_installation_default(self):
oauth_flow = AsyncOAuthFlow(
settings=AsyncOAuthSettings(
client_id="111.222",
Expand All @@ -109,6 +109,24 @@ async def test_handle_installation(self):
assert resp.headers.get("content-length") == ["565"]
assert "https://slack.com/oauth/v2/authorize?state=" in resp.body

@pytest.mark.asyncio
async def test_handle_installation_no_rendering(self):
oauth_flow = AsyncOAuthFlow(
settings=AsyncOAuthSettings(
client_id="111.222",
client_secret="xxx",
scopes=["chat:write", "commands"],
installation_store=FileInstallationStore(),
install_page_rendering_enabled=False, # disabled
state_store=FileOAuthStateStore(expiration_seconds=120),
)
)
req = AsyncBoltRequest(body="")
resp = await oauth_flow.handle_installation(req)
assert resp.status == 302
location_header = resp.headers.get("location")[0]
assert "https://slack.com/oauth/v2/authorize?state=" in location_header

@pytest.mark.asyncio
async def test_handle_callback(self):
oauth_flow = AsyncOAuthFlow(
Expand Down