Skip to content

App installation failing with invalid browser on lambda, even with state set #366

Description

@Bhavya6187

(Filling out the following details about bugs will help us solve your issue sooner.)

The slack_bolt version

slack-bolt==1.6.1
slack-sdk==3.6.0

Python runtime version

Python 3.9.5

OS info

ProductName: macOS
ProductVersion: 11.4
BuildVersion: 20F71

Steps to reproduce:

I am following the lambda oauth example here and added some extra settings to help debug.

from slack_bolt import App, BoltResponse, BoltRequest
from slack_bolt.adapter.aws_lambda import SlackRequestHandler
from slack_bolt.adapter.aws_lambda.lambda_s3_oauth_flow import LambdaS3OAuthFlow
from slack_bolt.oauth.callback_options import CallbackOptions, SuccessArgs, FailureArgs
from slack_bolt.oauth.oauth_settings import OAuthSettings

def success(args: SuccessArgs) -> BoltResponse:
    # Do anything here ...
    # Call the default handler to return HTTP response
    return args.default.success(args)
    # return BoltResponse(status=200, body="Thanks!")


def failure(args: FailureArgs) -> BoltResponse:
    print("status_code - ", args.suggested_status_code)
    print("reason - ", args.reason)
    failure_map = {
        "reason": args.reason,
        "status_code": args.suggested_status_code,
        "error": args.error
    }
    return BoltResponse(status=args.suggested_status_code, body=str(failure_map))

app = App(
    process_before_response=True,
    oauth_flow=LambdaS3OAuthFlow(
        settings=OAuthSettings(callback_options=CallbackOptions(success=success, failure=failure))
    ),
)

def handler(event, context):
    slack_handler = SlackRequestHandler(app=app)
    return slack_handler.handle(event, context)

These are the url's I've made on API Gateway

Screen Shot 2021-06-05 at 11 48 20 PM

Expected result:

Expected login to go through

Actual result:

Fails with output -
{'reason': 'invalid_browser', 'status_code': 400, 'error': None}
The problem in #248 seems to be related to state not set, however I can see both state and code set in this case. Am I missing something here?

Requirements

slack_sdk
slack-bolt
requests~=2.25.1

Activity

  1. seratch commented on Jun 6, 2021

    @seratch
    Contributor

    Hi @Bhavya6187, thanks for asking the question!

    The error indicates two possibilities:

    • The installer didn't go through the OAuth flow from the install URL, which redirects users to Slack's authorize URL with state parameter
    • The install URL didn't set cookie for the state value for some reason

    In your case, the second one may be the reason as you observed the query string has valid state parameter.

    By default, the install URL has set-cookie response header like set-cookie: slack-app-oauth-state=xxx-xxx-xxx-xxx-xxx; Secure; HttpOnly; Path=/; Max-Age=600. Check the browser developer tool to see how it's working with your app.

    A common cause of your situation is that the install URL does not start with https:// but http://. If so, the situation may arise as the set-cookie has the Secure; attribute. If that's not the case, check your AWS infra settings again.

    To learn how the part works, check the following source code:

    If you have some reason that you don't want to make the cookie validation functional, you can have your own OAuthFlow that inherits the LambdaS3OAuthFlow and overrides def handle_callback(self, request: BoltRequest) -> BoltResponse: method to have only the parts necessary for you.

  2. Bhavya6187 commented on Jun 6, 2021

    @Bhavya6187
    Author

    Thanks for replying @seratch, these pointers were incredibly helpful. I did verify the https link in install url, and looked at the developer tools, and looks like the cookie values are set, but they are not matching. It is failing at this line - https://github.com/slackapi/python-slack-sdk/blob/v3.6.0/slack_sdk/oauth/state_utils/__init__.py#L55

    When on /slack/install the value of cookie is -
    slack-app-oauth-state=fb913dce-f7c7-49ad-8f4a-829a1b341e5f

    After the oauth flow the values are -
    'state': '6ba9b705-99e1-4ab5-9b03-1eaa9de3b5db'
    cookie - 'slack-app-oauth-state=fb913dce-f7c7-49ad-8f4a-829a1b341e5f'

    I can remove the cookie validation by extending LambdaS3OAuthFlow as a last resort, but was wondering what might be the reason behind mismatch of values here?

  3. seratch commented on Jun 7, 2021

    @seratch
    Contributor

    Hi @Bhavya6187, I'm not sure what the cause of your situation is yet.

    I would recommend checking all the communications with a browser before the user redirection to https://slack.com/oauth/v2/authorize?state={...}&client_id=111.222&scope={...}&user_scope={...} URL. Perhaps, the state parameter in the redirection might not be different from the cookie value set by /slack/install page response for some reason.

  4. Bhavya6187 commented on Jun 7, 2021

    @Bhavya6187
    Author

    @seratch Looks like the state value in the cookie and the state param in the redirect url generated are not the same. Looking at this line - https://github.com/slackapi/bolt-python/blob/main/slack_bolt/oauth/oauth_flow.py#L158 it looks like the state variable set in the cookie should be the same as the one in the url, but that does not look to be the case.

    Any idea what might be missing here?

  5. seratch commented on Jun 7, 2021

    @seratch
    Contributor

    @Bhavya6187 As you see, the method is quite simple. As long as your app call the method only one time, your situation should not arise. Therefore, I'm guessing that your app may be repeating the state generation for some reason (e.g., redirecting users multiple times). I'm unable to tell anything further with given information.

    To narrow the issue down, I would recommend deploying the example as-is first. Running the following script (after configuring required env variables) should work for you:

    The example app handles everything (= GET /slack/install, POST /slack/event, and GET /slack/oauth_redirect) with a single endpoint. The default path would be https://{your public domain}/default/bolt_py_function but you can customize it by changing this part.

    Once you've confirmed the example works, identifying the issue that your app has can be easier.

  6. Bhavya6187 commented on Jun 9, 2021

    @Bhavya6187
    Author

    @seratch You're right that is the issue. After "/slack/install", there is a second call being made to get 'favicon.ico', which ends up trigerring the path of /slack/install again, changing the cookie value. The routing happens at this line - https://github.com/slackapi/bolt-python/blob/v1.6.1/slack_bolt/adapter/aws_lambda/handler.py#L57

    I was able to resolve it by adding <link rel="icon" href="data:,"> to the head section of the html here - https://github.com/slackapi/bolt-python/blob/v1.6.1/slack_bolt/oauth/internals.py#L76 which stops the browser from requesting it.

    Let me know if there's a more graceful solution than that. I'll close this issue in the meantime.

    Thanks a lot for your pointers, they were really helpful.

  7. seratch commented on Jun 9, 2021

    @seratch
    Contributor

    Hi @Bhavya6187, thanks for sharing this and that makes sense!

    I was able to resolve it by adding to the head section of the html here - https://github.com/slackapi/bolt-python/blob/v1.6.1/slack_bolt/oauth/internals.py#L76 which stops the browser from requesting it.

    This looks good enough for avoiding the possible confusion. If you have time, would you mind sending a pull request to add the tag to the default template? I can work on it later, too.

  8. Bhavya6187 commented on Jun 10, 2021

    @Bhavya6187
    Author

    Sure @seratch, I've created #375 for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions