Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OAuth2 Refresh Token Broken #2156

Closed
3 tasks done
ZachHandley opened this issue Aug 10, 2023 · 1 comment
Closed
3 tasks done

OAuth2 Refresh Token Broken #2156

ZachHandley opened this issue Aug 10, 2023 · 1 comment
Labels
Invalid This is not valid No Reproduction This is not reproducible

Comments

@ZachHandley
Copy link

ZachHandley commented Aug 10, 2023

Summary

OAuth2 Refresh Token is unclear, buggy, and doesn't work

Reproduction Steps

I stole the code here #1806 for the refresh token, and it just refuses to work. I basically recreate an OAuth2 handler as a class that extends the other, then I set the access token to the stored token in my database (the full token) and then it should refresh, but instead I'm getting an invalid access token and blah blah. I really don't understand how it works and this doesn't seem like a new issue I'm raising here, but what else can I do when it isn't fixed and I can't figure it out so here I am again, sorry Harmon

OAuth a user, then, in a separate function try refreshing the token 2 hours later with not the same Auth client that you initially created (I have multiple users on the same OAuth flow, so the saved token won't work always)

Minimal Reproducible Example

class MyOAuth2UserHandler(tweepy.OAuth2UserHandler):
    # Kudos https://github.com/tweepy/tweepy/pull/1806

    def refresh_token(self, refresh_token):
        new_token = super().refresh_token(
            "https://api.twitter.com/2/oauth2/token",
            refresh_token=refresh_token,
            body=f"grant_type=refresh_token&client_id={self.client_id}",
        )
        return new_token
def check_refresh_token() -> tweepy.Client:
    user_id = session.get("user_id")
    if not db_manager.check_twitter_user(user_id):
        return "Error: User has not authenticated with Twitter."
    # get user's access token and access token secret from database
    twitter_user = db_manager.get_twitter_user(user_id)
    full_token = twitter_user.get("twitter_access_token")
    expires_at = twitter_user.get("expires_at")
    expiry_date = datetime.fromisoformat(expires_at)
    now = datetime.now().replace(tzinfo=expiry_date.tzinfo)
    print(f"Access token expires at: {expiry_date}\nIt is currently {now}")
    if now > expiry_date:
        print(f"Client ID: {CLIENT_ID}\nClient Secret: {CLIENT_SECRET}")
        newAuth = MyOAuth2UserHandler(
            client_id=CLIENT_ID,
            client_secret=CLIENT_SECRET,
            redirect_uri="https://localhost:5172/callback",
            scope=SCOPES,
        )
        print(f"Access token is {full_token}")
        access_token = newAuth.refresh_token(
            refresh_token=twitter_user["twitter_refresh_token"],
        )
        save_to_db(
            user_id=user_id,
            twitter_user=twitter_user,
            access_token=access_token,
            refresh_token=twitter_user["twitter_refresh_token"],
        )
    client = tweepy.Client(access_token["access_token"], wait_on_rate_limit=True)
    return client

Expected Results

The token gets refreshed

Actual Results

Access token is {'token_type': 'bearer', 'expires_in': 7200, 'access_token': 'SlYxSG_MY_TOKEN_dXNjb216OjE2OTE2MzUzMTM1OTg6MTowOmF0OjE', 'scope': ['follows.read', 'offline.access', 'tweet.write', 'like.read', 'users.read', 'tweet.read'], 'refresh_token': 'R2paaWIyVFV6ZWFOaTk0WTAtR25QSUktMG_MY_REFRESH_TOKEN_elc5OjE2OTE2MzUzMTM1OTg6MToxOnJ0OjE', 'expires_at': 1691642513.517365}
127.0.0.1 - - [09/Aug/2023 22:39:14] "POST /create_tweet/296759788358860801 HTTP/1.1" 500 -
Traceback (most recent call last):
  File "/Users/zachhandley/.pyenv/versions/3.11.4/lib/python3.11/site-packages/flask/app.py", line 2213, in __call__
    return self.wsgi_app(environ, start_response)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/zachhandley/.pyenv/versions/3.11.4/lib/python3.11/site-packages/flask/app.py", line 2193, in wsgi_app
    response = self.handle_exception(e)
               ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/zachhandley/.pyenv/versions/3.11.4/lib/python3.11/site-packages/flask/app.py", line 2190, in wsgi_app
    response = self.full_dispatch_request()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/zachhandley/.pyenv/versions/3.11.4/lib/python3.11/site-packages/flask/app.py", line 1486, in full_dispatch_request
    rv = self.handle_user_exception(e)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/zachhandley/.pyenv/versions/3.11.4/lib/python3.11/site-packages/flask/app.py", line 1484, in full_dispatch_request
    rv = self.dispatch_request()
         ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/zachhandley/.pyenv/versions/3.11.4/lib/python3.11/site-packages/flask/app.py", line 1469, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/zachhandley/Documents/GitHub/TwitterPy/server.py", line 164, in create_tweet
    write_tweet(user_id=user_id, text=text)
  File "/Users/zachhandley/Documents/GitHub/TwitterPy/server.py", line 212, in write_tweet
    client = check_refresh_token()
             ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/zachhandley/Documents/GitHub/TwitterPy/server.py", line 194, in check_refresh_token
    access_token = auth.refresh_token(
                   ^^^^^^^^^^^^^^^^^^^
  File "/Users/zachhandley/Documents/GitHub/TwitterPy/server.py", line 42, in refresh_token
    new_token = super().refresh_token(
                ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/zachhandley/.pyenv/versions/3.11.4/lib/python3.11/site-packages/requests_oauthlib/oauth2_session.py", line 452, in refresh_token
    self.token = self._client.parse_request_body_response(r.text, scope=self.scope)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/zachhandley/.pyenv/versions/3.11.4/lib/python3.11/site-packages/oauthlib/oauth2/rfc6749/clients/base.py", line 427, in parse_request_body_response
    self.token = parse_token_response(body, scope=scope)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/zachhandley/.pyenv/versions/3.11.4/lib/python3.11/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 441, in parse_token_response
    validate_token_parameters(params)
  File "/Users/zachhandley/.pyenv/versions/3.11.4/lib/python3.11/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 448, in validate_token_parameters
    raise_from_error(params.get('error'), params)
  File "/Users/zachhandley/.pyenv/versions/3.11.4/lib/python3.11/site-packages/oauthlib/oauth2/rfc6749/errors.py", line 399, in raise_from_error
    raise cls(**kwargs)
oauthlib.oauth2.rfc6749.errors.InvalidClientIdError: (invalid_request) Value passed for the token was invalid.

I've verified my Client ID just now by copying it and pasting it in and running it again, and maybe I'm doing something wrong but I'm just at my wits end with trying to understand why it's not working and reading through online articles and what not

Twitter API Access Plan

Basic

Tweepy Version

4.14.0

Checklist

  • I have searched for duplicate issues.
  • If applicable, I have shown the entire traceback.
  • If applicable, I have removed any visible credentials from my code and/or screenshots.

Additional Context

I really just want to be able to refresh my users access

@ZachHandley ZachHandley added the Unconfirmed Bug This is a bug report that has not been triaged yet label Aug 10, 2023
@Harmon758
Copy link
Member

This not a minimal nor reproducible example.

In fact, your traceback does not match your code.

As you can see from the traceback though, Tweepy does not touch requests_oauthlib.OAuth2Session.refresh_token, so this is not an issue with Tweepy.

@Harmon758 Harmon758 closed this as not planned Won't fix, can't repro, duplicate, stale Aug 10, 2023
@Harmon758 Harmon758 added Invalid This is not valid No Reproduction This is not reproducible and removed Unconfirmed Bug This is a bug report that has not been triaged yet labels Aug 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Invalid This is not valid No Reproduction This is not reproducible
Projects
None yet
Development

No branches or pull requests

2 participants