Python - SDK - AuthAPIError - Bad Request

21 views
Skip to first unread message

James Carr

unread,
Apr 15, 2024, 1:41:04 PMApr 15
to Discuss
I am redirecting the user through the auth flow, capturing the code and getting a token. It works up until  oauth2_exchange_code_for_tokens(). After the user approves on the Globus side, it sends the auth code back to my app, which throws up the error. 

@globus_ns.route("/globus_login/")
def get(self):
        client = GlobusOperations().general_auth_client()
        client.oauth2_start_flow(request.url)
        if "code" not in request.args:
            auth_uri = client.oauth2_get_authorize_url()
            return redirect(auth_uri)
        else:
            code = request.args.get("code")
            token = client.oauth2_exchange_code_for_tokens(code)
[other code to handle token]

globus_sdk.services.auth.errors.AuthAPIError: ('POST', 'https://auth.globus.org/v2/oauth2/token', 'Basic', 400, 'Error', 'Bad Request')

Client code FYI:
    def general_auth_client(self):
            return globus_sdk.ConfidentialAppAuthClient(
                    client_id=Config.GLOBUS_CLIENT_ID, client_secret=Config.GLOBUS_CLIENT_SECRET)

Some debugging info:
[2024-04-15 10:21:16,944] DEBUG in authorization_code: Performing Authorization Code auth_code exchange. Sending client_id and client_secret
[2024-04-15 10:21:16,944] INFO in base_login_client: Fetching new token from Globus Auth
[2024-04-15 10:21:16,944] DEBUG in client: POST to /v2/oauth2/token with query_params None
[2024-04-15 10:21:16,944] DEBUG in client: request will hit URL: https://auth.globus.org/v2/oauth2/token
[2024-04-15 10:21:16,944] DEBUG in requests: starting request for https://auth.globus.org/v2/oauth2/token
[2024-04-15 10:21:16,944] DEBUG in requests: transport request state initialized
[2024-04-15 10:21:16,944] DEBUG in requests: transport request retry cycle. attempt=0
[2024-04-15 10:21:16,944] DEBUG in requests: request about to send
[2024-04-15 10:21:17,529] DEBUG in requests: request success, still check should-retry
[2024-04-15 10:21:17,529] DEBUG in retry: ran retry check (default_check_expired_authorization) => RetryCheckResult.no_decision
[2024-04-15 10:21:17,529] DEBUG in retry: ran retry check (default_check_request_exception) => RetryCheckResult.no_decision
[2024-04-15 10:21:17,530] DEBUG in retry: ran retry check (default_check_retry_after_header) => RetryCheckResult.no_decision
[2024-04-15 10:21:17,530] DEBUG in retry: ran retry check (default_check_transient_error) => RetryCheckResult.no_decision
[2024-04-15 10:21:17,531] INFO in requests: request done (success)
[2024-04-15 10:21:17,531] DEBUG in client: request made to URL: https://auth.globus.org/v2/oauth2/token
[2024-04-15 10:21:17,531] DEBUG in client: request completed with (error) response code: 400

Could it relate to "query_params None" ?
If there is anything else I can provide to help troubleshoot, please let me know. 

Karl Kornel

unread,
Apr 15, 2024, 1:50:32 PMApr 15
to James Carr, Discuss

Hi James,

 

The `oauth2_start_flow` method returns an instance of a flow-manager object.  Could you try holding on to that instance, and then calling that instance’s ` get_authorize_url` and `exchange_code_for_tokens` methods?

 

~ Karl

 

To unsubscribe from this group and stop receiving emails from it, send an email to discuss+u...@globus.org.

James Carr

unread,
Apr 15, 2024, 1:59:38 PMApr 15
to Discuss, akko...@stanford.edu, James Carr
Using: auth_flow = client.oauth2_start_flow(request.url)
and: auth_uri = auth_flow.oauth2_get_authorize_url()

AttributeError: 'GlobusAuthorizationCodeFlowManager' object has no attribute 'oauth2_get_authorize_url'

Also passing auth_flow as a parameter fails due to too many parameters, it must be empty. 

Karl Kornel

unread,
Apr 15, 2024, 2:03:01 PMApr 15
to James Carr, Discuss

Hi James,

 

Two questions for you, referencing your original post:

 

1. What is the type of the object returned by `client = GlobusOperations().general_auth_client()`?  Is it a NativeAppAuthClient or a ConfidentialAppAuthClient?

 

2. What is `request.url`?  Is it the URL that the user needs to be redirected to, after the Globus auth is completed?

 

~ Karl

James Carr

unread,
Apr 15, 2024, 2:14:13 PMApr 15
to Discuss, akko...@stanford.edu, James Carr
Resolved! 
Karl, you asked the right questions. 

1. <class 'globus_sdk.services.auth.client.confidential_client.ConfidentialAppAuthClient'>

2. Correct. It's supposed to return the current url by referencing the current route's function; however I changed it to be a hardcoded string of the url and it works!
I suspect the current route only allows GET requests and the redirect needs to be a post? 

This works:
        client = GlobusOperations().general_auth_client()
        client.oauth2_start_flow(redirect_uri)

Thank you!
-James

Karl Kornel

unread,
Apr 16, 2024, 3:37:09 PMApr 16
to James Carr, Discuss

Hi James,

 

What you’re running into is a protection against item 1 of OWASP’s “OAuth 2.0 Essential Basics”: Clients and Authorization Server must not expose URLs that forward the user's browser to arbitrary URIs obtained from a query parameter ("open redirectors") which can enable exfiltration of authorization codes and access tokens.

 

The redirect URL you pass to Globus Auth must be one of the URLs that you’ve specified, when you set up the App on the Globus Developers site.

 

If you want to pass some additional information on to your app, OAuth 2.0 (and Globus Auth) provides the “state” parameter: You provide some string as the state.  When Globus Auth redirects the client back to your chosen redirect URL, the state will be one of the parameters (along with the code).

 

One web app I regularly use does the following, whenever I try to visit a web page without having logged in:

 

1. Generate a random UUID

2a. Set a cookie, containing the UUID and the URL I was trying to visit.

2b. Redirect me to an OAuth 2.0 login, with the UUID as the state.

3. After I’m redirected back to the application, compare the UUID from the state with my browser cookies:

• If the UUID is present in the cookie, and it matches the UUID from the state, I am authenticated, and redirected to the place I originally wanted to go.

• In any other case, the app revokes the just-issued token, then returns an error.

 

As for request types: All of the OAuth 2.0 operations are GET requests, with parameters passed via the URL query string.

Reply all
Reply to author
Forward
0 new messages