Issue Description
When using base64 encoded state values that include padding (ending in ==), the OAuth flow fails with invalid_browser. This occurs because browsers may add quotes around cookie values containing special characters, but the is_valid_browser validation doesn't account for these quotes.
Environment
- slack_bolt: 1.22.0
- slack_sdk: 3.34.0
- Python: 3.10.16
- Browser: Chrome 132.0.6834.160 (arm64) (issue likely affects other browsers)
Steps to Reproduce
- Implement a custom
OAuthStateStore that issues base64 encoded strings with padding
- Initiate the standard OAuth flow
- Observe the flow fails at the final redirect with
invalid_browser
Investigation
The issue occurs in OAuthStateUtils.is_valid_browser():
class OAuthStateUtils:
...
def is_valid_browser(
self,
state: Optional[str],
request_headers: Dict[str, Union[str, Sequence[str]]],
) -> bool:
if state is None or request_headers is None or request_headers.get("cookie", None) is None:
return False
cookies = request_headers["cookie"]
if isinstance(cookies, str):
cookies = [cookies]
for cookie in cookies:
values = cookie.split(";")
for value in values:
if value.strip() == f"{self.cookie_name}={state}":
return True
return False
When the state contains base64 padding (== - might as well for =), browsers add quotes around the cookie value:
# What we expect:
state = 'eyJ...J9IA==' (prior appding self.cookie_name)
value = 'slack-app-oauth-state=eyJ...J9IA=='
# What actually happens:
value = 'slack-app-oauth-state="eyJ...J9IA=="' # Browser adds quotes to the set cookie
This doesn't happen with unpadded base64 values, which is why the issue only affects certain state values.
Proposed Fix
Add quote stripping to the cookie value comparison:
class FixedStateUtils(OAuthStateUtils):
def is_valid_browser(
self,
state: str | None,
request_headers: dict[str, str | Sequence[str]],
) -> bool:
if state is None or request_headers is None or request_headers.get("cookie", None) is None:
return False
cookies = request_headers["cookie"]
if isinstance(cookies, str):
cookies = [cookies]
for cookie in cookies:
values = cookie.split(";")
for value in values:
if value.strip().replace('"', "").replace("'", "") == f"{self.cookie_name}={state}":
return True
return False
Temporary Workaround
Until this is fixed, you can use the patched version by configuring your OAuth settings:
oauth_settings.state_utils = FixedStateUtils(
cookie_name=oauth_settings.state_cookie_name,
expiration_seconds=oauth_settings.state_expiration_seconds,
)
Let me know if you need any help for further reproduction.
Issue Description
When using base64 encoded state values that include padding (ending in
==), the OAuth flow fails withinvalid_browser. This occurs because browsers may add quotes around cookie values containing special characters, but theis_valid_browservalidation doesn't account for these quotes.Environment
Steps to Reproduce
OAuthStateStorethat issues base64 encoded strings with paddinginvalid_browserInvestigation
The issue occurs in
OAuthStateUtils.is_valid_browser():When the state contains base64 padding (
==- might as well for=), browsers add quotes around the cookie value:This doesn't happen with unpadded base64 values, which is why the issue only affects certain state values.
Proposed Fix
Add quote stripping to the cookie value comparison:
Temporary Workaround
Until this is fixed, you can use the patched version by configuring your OAuth settings:
Let me know if you need any help for further reproduction.