Skip to content

Commit 512a53c

Browse files
committed
Fix #183 Easier way to configure the installation URL as the direct install URL on App Directory
1 parent 899ce76 commit 512a53c

File tree

6 files changed

+90
-22
lines changed

6 files changed

+90
-22
lines changed

slack_bolt/oauth/async_oauth_flow.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -162,19 +162,30 @@ def sqlite3(
162162
async def handle_installation(self, request: AsyncBoltRequest) -> BoltResponse:
163163
state = await self.issue_new_state(request)
164164
url = await self.build_authorize_url(state, request)
165-
html = await self.build_install_page_html(url, request)
166165
set_cookie_value = self.settings.state_utils.build_set_cookie_for_new_state(
167166
state
168167
)
169-
return BoltResponse(
170-
status=200,
171-
body=html,
172-
headers={
173-
"Content-Type": "text/html; charset=utf-8",
174-
"Content-Length": len(bytes(html, "utf-8")),
175-
"Set-Cookie": [set_cookie_value],
176-
},
177-
)
168+
if self.settings.install_page_rendering_enabled:
169+
html = await self.build_install_page_html(url, request)
170+
return BoltResponse(
171+
status=200,
172+
body=html,
173+
headers={
174+
"Content-Type": "text/html; charset=utf-8",
175+
"Content-Length": len(bytes(html, "utf-8")),
176+
"Set-Cookie": [set_cookie_value],
177+
},
178+
)
179+
else:
180+
return BoltResponse(
181+
status=302,
182+
body="",
183+
headers={
184+
"Content-Type": "text/html; charset=utf-8",
185+
"Location": url,
186+
"Set-Cookie": [set_cookie_value],
187+
},
188+
)
178189

179190
# ----------------------
180191
# Internal methods for Installation

slack_bolt/oauth/async_oauth_settings.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class AsyncOAuthSettings:
3232
redirect_uri: Optional[str]
3333
# Handler configuration
3434
install_path: str
35+
install_page_rendering_enabled: bool
3536
redirect_uri_path: str
3637
callback_options: Optional[CallbackOptions] = None
3738
success_url: Optional[str]
@@ -63,6 +64,7 @@ def __init__(
6364
redirect_uri: Optional[str] = None,
6465
# Handler configuration
6566
install_path: str = "/slack/install",
67+
install_page_rendering_enabled: bool = True,
6668
redirect_uri_path: str = "/slack/oauth_redirect",
6769
callback_options: Optional[CallbackOptions] = None,
6870
success_url: Optional[str] = None,
@@ -86,6 +88,7 @@ def __init__(
8688
:param user_scopes: Check the value in Settings > Manage Distribution
8789
:param redirect_uri: Check the value in Features > OAuth & Permissions > Redirect URLs
8890
:param install_path: The endpoint to start an OAuth flow (Default: /slack/install)
91+
:param install_page_rendering_enabled: Renders a web page for install_path access if True
8992
:param redirect_uri_path: The path of Redirect URL (Default: /slack/oauth_redirect)
9093
:param callback_options: Give success/failure functions f you want to customize callback functions.
9194
:param success_url: Set a complete URL if you want to redirect end-users when an installation completes.
@@ -119,6 +122,7 @@ def __init__(
119122
self.install_path = install_path or os.environ.get(
120123
"SLACK_INSTALL_PATH", "/slack/install"
121124
)
125+
self.install_page_rendering_enabled = install_page_rendering_enabled
122126
self.redirect_uri_path = redirect_uri_path or os.environ.get(
123127
"SLACK_REDIRECT_URI_PATH", "/slack/oauth_redirect"
124128
)

slack_bolt/oauth/oauth_flow.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -157,19 +157,30 @@ def sqlite3(
157157
def handle_installation(self, request: BoltRequest) -> BoltResponse:
158158
state = self.issue_new_state(request)
159159
url = self.build_authorize_url(state, request)
160-
html = self.build_install_page_html(url, request)
161160
set_cookie_value = self.settings.state_utils.build_set_cookie_for_new_state(
162161
state
163162
)
164-
return BoltResponse(
165-
status=200,
166-
body=html,
167-
headers={
168-
"Content-Type": "text/html; charset=utf-8",
169-
"Content-Length": len(bytes(html, "utf-8")),
170-
"Set-Cookie": [set_cookie_value],
171-
},
172-
)
163+
if self.settings.install_page_rendering_enabled:
164+
html = self.build_install_page_html(url, request)
165+
return BoltResponse(
166+
status=200,
167+
body=html,
168+
headers={
169+
"Content-Type": "text/html; charset=utf-8",
170+
"Content-Length": len(bytes(html, "utf-8")),
171+
"Set-Cookie": [set_cookie_value],
172+
},
173+
)
174+
else:
175+
return BoltResponse(
176+
status=302,
177+
body="",
178+
headers={
179+
"Content-Type": "text/html; charset=utf-8",
180+
"Location": url,
181+
"Set-Cookie": [set_cookie_value],
182+
},
183+
)
173184

174185
# ----------------------
175186
# Internal methods for Installation

slack_bolt/oauth/oauth_settings.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class OAuthSettings:
2727
redirect_uri: Optional[str]
2828
# Handler configuration
2929
install_path: str
30+
install_page_rendering_enabled: bool
3031
redirect_uri_path: str
3132
callback_options: Optional[CallbackOptions] = None
3233
success_url: Optional[str]
@@ -58,6 +59,7 @@ def __init__(
5859
redirect_uri: Optional[str] = None,
5960
# Handler configuration
6061
install_path: str = "/slack/install",
62+
install_page_rendering_enabled: bool = True,
6163
redirect_uri_path: str = "/slack/oauth_redirect",
6264
callback_options: Optional[CallbackOptions] = None,
6365
success_url: Optional[str] = None,
@@ -81,6 +83,7 @@ def __init__(
8183
:param user_scopes: Check the value in Settings > Manage Distribution
8284
:param redirect_uri: Check the value in Features > OAuth & Permissions > Redirect URLs
8385
:param install_path: The endpoint to start an OAuth flow (Default: /slack/install)
86+
:param install_page_rendering_enabled: Renders a web page for install_path access if True
8487
:param redirect_uri_path: The path of Redirect URL (Default: /slack/oauth_redirect)
8588
:param callback_options: Give success/failure functions f you want to customize callback functions.
8689
:param success_url: Set a complete URL if you want to redirect end-users when an installation completes.
@@ -113,6 +116,7 @@ def __init__(
113116
self.install_path = install_path or os.environ.get(
114117
"SLACK_INSTALL_PATH", "/slack/install"
115118
)
119+
self.install_page_rendering_enabled = install_page_rendering_enabled
116120
self.redirect_uri_path = redirect_uri_path or os.environ.get(
117121
"SLACK_REDIRECT_URI_PATH", "/slack/oauth_redirect"
118122
)

tests/slack_bolt/oauth/test_oauth_flow.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def test_instantiation(self):
4040
assert oauth_flow.logger is not None
4141
assert oauth_flow.client is not None
4242

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

61+
# https://github.com/slackapi/bolt-python/issues/183
62+
# For direct install URL suppport
63+
def test_handle_installation_no_rendering(self):
64+
oauth_flow = OAuthFlow(
65+
settings=OAuthSettings(
66+
client_id="111.222",
67+
client_secret="xxx",
68+
scopes=["chat:write", "commands"],
69+
user_scopes=["search:read"],
70+
installation_store=FileInstallationStore(),
71+
install_page_rendering_enabled=False, # disabled
72+
state_store=FileOAuthStateStore(expiration_seconds=120),
73+
)
74+
)
75+
req = BoltRequest(body="")
76+
resp = oauth_flow.handle_installation(req)
77+
assert resp.status == 302
78+
location_header = resp.headers.get("location")[0]
79+
assert "https://slack.com/oauth/v2/authorize?state=" in location_header
80+
6181
def test_scopes_as_str(self):
6282
settings = OAuthSettings(
6383
client_id="111.222",

tests/slack_bolt_async/oauth/test_async_oauth_flow.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ async def test_instantiation_non_async_settings_to_app(self):
9292
)
9393

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

112+
@pytest.mark.asyncio
113+
async def test_handle_installation_no_rendering(self):
114+
oauth_flow = AsyncOAuthFlow(
115+
settings=AsyncOAuthSettings(
116+
client_id="111.222",
117+
client_secret="xxx",
118+
scopes=["chat:write", "commands"],
119+
installation_store=FileInstallationStore(),
120+
install_page_rendering_enabled=False, # disabled
121+
state_store=FileOAuthStateStore(expiration_seconds=120),
122+
)
123+
)
124+
req = AsyncBoltRequest(body="")
125+
resp = await oauth_flow.handle_installation(req)
126+
assert resp.status == 302
127+
location_header = resp.headers.get("location")[0]
128+
assert "https://slack.com/oauth/v2/authorize?state=" in location_header
129+
112130
@pytest.mark.asyncio
113131
async def test_handle_callback(self):
114132
oauth_flow = AsyncOAuthFlow(

0 commit comments

Comments
 (0)