I was following this guide https://developer.twitter.com/en/docs/tutorials/creating-a-twitter-bot-with-python–oauth-2-0–and-v2-of-the-twi of how to build a bot and am still currently learning about oauth 2.0 with pkce and will remodify/refactor the code when working. (I do have offlince.access scope as well).
Seems like it is kind of the same issue as this one : Refresh token expiring (with offline.access scope) - #13 by dewey
I was able to get the script to run continuously. It would check twitter every 30 seconds if anyone has mentioned my Twitter handle in the previous past 2 minutes then it would reply to that tweet. It would work for a day or 2 at best then would get the error below.
I thought it might of been a access token rate issue about the 30 seconds thing, so I changed it to 1 minute and was not getting the error anymore, or so I thought. After 4 days of continuously running the script it gave the same error below.
I’ve also adding logging to the script to see if the refresh and access tokens really did change when it refreshes the token and it did.
From the error it seems like it is from the oauths “refresh_token” method, in there it seems to make a call to Twitter using the refresh token that was retrieved from Redis so it can get new refresh and access tokens. But it seems like that refresh token from Redis is invalid?
One work-around I found to this issue was to re-authenticate by manually logging in again to get new tokens and storing it back into Redis again, then it would work for a few days then the error would present itself.
My question is after manually re-authenticating, then letting the script run it would work, but after a few days it would fail.
Why would it throw that error when it was working fine before but after a few days the script is then unable to retrieve new tokens, does that mean the refresh token retrieved from Redis was invalid? If so then why fail later but not before? Could the refresh token have expired sooner?
Note*: Both the refresh and access tokens are refreshed every minute so the refresh token should still be valid.
twitter = main.make_token()
logging.info(f"Twitter Token: {twitter}")
client_id = super_keys.CLIENT_ID
client_secret = super_keys.CLIENT_SECRET
token_url = "https://api.twitter.com/2/oauth2/token"
t = main.r.get("token")
logging.info(f"Variable 't' assigned: {t}")
logging.debug(f"Reformatting t:")
bb_t = t.decode("utf8").replace("'", '"')
logging.info(f"bb_t assigned: {bb_t}")
data = json.loads(bb_t)
logging.info(f"json data assigned: {data}")
logging.debug(f"Going inside refresh_token:")
refreshed_token = twitter.refresh_token(
client_id=client_id,
client_secret=client_secret,
token_url=token_url,
refresh_token=data["refresh_token"],
)
#Reformats and stores new token into redis
st_refreshed_token = '"{}"'.format(refreshed_token)
j_refreshed_token = json.loads(st_refreshed_token)
pain.r.set("token", j_refreshed_token)
return refreshed_token
def doing_something():
mm_status = main.recent_mention(get_refresh_token())
------------------------------------------------------------------------------
main.py
def recent_mention(token):
# Get the current timestamp in UTC
timestamp = time.time()
# Convert the timestamp to a datetime object in UTC
utc_time = datetime.utcfromtimestamp(timestamp)
# Format the datetime object in the desired format
formatted_time = utc_time.strftime('%Y-%m-%dT%H:%M:%SZ')
# Subtract one hour from the time
min_ago = utc_time - timedelta(minutes=2)
# Format the resulting datetime object in the desired format
formatted_time = min_ago .strftime('%Y-%m-%dT%H:%M:%SZ')
url = "https://api.twitter.com/2/tweets/search/recent"
params = {
"query":"@FlipperStockBot",
'start_time': formatted_time
}
headers={
"Authorization": "Bearer {}".format(token["access_token"])
}
response = requests.get(url, params=params, headers=headers)
return response
20-Dec-22 21:32:08 - 112: INFO - get_refresh_token - Twitter Token: <requests_oauthlib.oauth2_session.OAuth2Session object at 0x7fb702ba60>
20-Dec-22 21:32:08 - 126: INFO - get_refresh_token - Variable 't' assigned: b"{'token_type': 'bearer', 'expires_in': 7200, 'access_token': 'dVFrWFNsb1ZQUUtYeFVUVzQweTZ2bWQ1NWR3Q2NfSDZuMU1EdUt3S09KQjcyOjE2NzE1OTM0OTEwNTg6MTowOmF0OjE', 'scope': ['tweet.write', 'users.read', 'tweet.read', 'offline.access'], 'refresh_token': 'UDJMdHJNV3hSY3RhaV9pRXVTYXlaNkMtMXVLQjVNOGFCUUl0eHp5QzJka0d2OjE2NzE1OTM0OTEwNTg6MTowOnJ0OjE', 'expires_at': 1671600691.0920045}"
20-Dec-22 21:32:08 - 128: DEBUG - get_refresh_token - Reformatting t:
20-Dec-22 21:32:08 - 130: INFO - get_refresh_token - bb_t assigned: {"token_type": "bearer", "expires_in": 7200, "access_token": "dVFrWFNsb1ZQUUtYeFVUVzQweTZ2bWQ1NWR3Q2NfSDZuMU1EdUt3S09KQjcyOjE2NzE1OTM0OTEwNTg6MTowOmF0OjE", "scope": ["tweet.write", "users.read", "tweet.read", "offline.access"], "refresh_token": "UDJMdHJNV3hSY3RhaV9pRXVTYXlaNkMtMXVLQjVNOGFCUUl0eHp5QzJka0d2OjE2NzE1OTM0OTEwNTg6MTowOnJ0OjE", "expires_at": 1671600691.0920045}
20-Dec-22 21:32:08 - 134: INFO - get_refresh_token - json data assigned: {'token_type': 'bearer', 'expires_in': 7200, 'access_token': 'dVFrWFNsb1ZQUUtYeFVUVzQweTZ2bWQ1NWR3Q2NfSDZuMU1EdUt3S09KQjcyOjE2NzE1OTM0OTEwNTg6MTowOmF0OjE', 'scope': ['tweet.write', 'users.read', 'tweet.read', 'offline.access'], 'refresh_token': 'UDJMdHJNV3hSY3RhaV9pRXVTYXlaNkMtMXVLQjVNOGFCUUl0eHp5QzJka0d2OjE2NzE1OTM0OTEwNTg6MTowOnJ0OjE', 'expires_at': 1671600691.0920045}
20-Dec-22 21:32:08 - 136: DEBUG - get_refresh_token - Going inside refresh_token:
20-Dec-22 21:32:08 - 282: DEBUG - refresh_token - Adding auto refresh key word arguments {}.
20-Dec-22 21:32:08 - 287: DEBUG - refresh_token - Prepared refresh token request body grant_type=refresh_token&client_id=Y0lvTDZXN2hKZlZldGNzYlcxbk06MTpjaQ&client_secret=D2cZhEZES7YKxiP4dMCnxMvXyg-zzzzzzz-mN0FYj5Jw_G3&scope=tweet.read+users.read+tweet.write+offline.access&refresh_token=UDJMdHJNV3hSY3RhaV9pRXVTYXlaNkMtMXVLQjVNOGFCUUl0eHp5QzJka0d2OjE2NzE1OTM0OTEwNTg6MTowOnJ0OjE
20-Dec-22 21:32:08 - 356: DEBUG - request - Requesting url https://api.twitter.com/2/oauth2/token using method POST.
20-Dec-22 21:32:08 - 357: DEBUG - request - Supplying headers {'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'} and data {'grant_type': 'refresh_token', 'client_id': 'Y0lvTDZXN2hKZlZldGNzYlcxbk06MTpjaQ', 'client_secret': 'D2cZhEZES7YKxiP4dMCnxMvXyg-zzzzzzz-mN0FYj5Jw_G3', 'scope': 'tweet.read users.read tweet.write offline.access', 'refresh_token': 'UDJMdHJNV3hSY3RhaV9pRXVTYXlaNkMtMXVLQjVNOGFCUUl0eHp5QzJka0d2OjE2NzE1OTM0OTEwNTg6MTowOnJ0OjE'}
20-Dec-22 21:32:08 - 358: DEBUG - request - Passing through key word arguments {'json': None, 'auth': None, 'timeout': None, 'verify': True, 'proxies': None}.
20-Dec-22 21:32:08 - 973: DEBUG - _new_conn - Starting new HTTPS connection (1): api.twitter.com:443
20-Dec-22 21:32:08 - 452: DEBUG - _make_request - https://api.twitter.com:443 "POST /2/oauth2/token HTTP/1.1" 400 103
20-Dec-22 21:32:08 - 299: DEBUG - refresh_token - Request to refresh token completed with status 400.
20-Dec-22 21:32:08 - 301: DEBUG - refresh_token - Response headers were {'date': 'Wed, 21 Dec 2022 03:32:08 GMT', 'perf': '7626143928', 'server': 'tsa_b', 'set-cookie': 'guest_id_marketing=v1%3A167159352873524022; Max-Age=63072000; Expires=Fri, 20 Dec 2024 03:32:08 GMT; Path=/; Domain=.twitter.com; Secure; SameSite=None, guest_id_ads=v1%3A167159352873524022; Max-Age=63072000; Expires=Fri, 20 Dec 2024 03:32:08 GMT; Path=/; Domain=.twitter.com; Secure; SameSite=None, personalization_id="v1_8F0j+T2snjNvfjVzp4X0Gg=="; Max-Age=63072000; Expires=Fri, 20 Dec 2024 03:32:08 GMT; Path=/; Domain=.twitter.com; Secure; SameSite=None, guest_id=v1%3A167159352873524022; Max-Age=63072000; Expires=Fri, 20 Dec 2024 03:32:08 GMT; Path=/; Domain=.twitter.com; Secure; SameSite=None', 'content-type': 'application/json;charset=UTF-8', 'cache-control': 'no-cache, no-store, max-age=0', 'content-length': '103', 'x-frame-options': 'SAMEORIGIN', 'content-encoding': 'gzip', 'x-transaction-id': 'fd13692cca3762bd', 'x-xss-protection': '0', 'content-disposition': 'attachment; filename=json.json', 'x-content-type-options': 'nosniff', 'strict-transport-security': 'max-age=631138519', 'x-response-time': '14', 'x-connection-hash': 'daab865401b97e1c6b7ee87dabe6758d64bb7c5419b0671049a3572c096f709d'} and content {"error":"invalid_request","error_description":"Value passed for the token was invalid."}.
20-Dec-22 21:32:08 - 303: DEBUG - refresh_token - Invoking 0 token response hooks.
File "/home/brooo/Python_Projects/FlipperTwitterBot/etg.py", line 137, in get_refresh_token
refreshed_token = twitter.refresh_token(
File "/usr/lib/python3/dist-packages/requests_oauthlib/oauth2_session.py", line 309, in refresh_token
self.token = self._client.parse_request_body_response(r.text, scope=self.scope)
File "/usr/lib/python3/dist-packages/oauthlib/oauth2/rfc6749/clients/base.py", line 421, in parse_request_body_response
self.token = parse_token_response(body, scope=scope)
File "/usr/lib/python3/dist-packages/oauthlib/oauth2/rfc6749/parameters.py", line 431, in parse_token_response
validate_token_parameters(params)
File "/usr/lib/python3/dist-packages/oauthlib/oauth2/rfc6749/parameters.py", line 438, in validate_token_parameters
raise_from_error(params.get('error'), params)
File "/usr/lib/python3/dist-packages/oauthlib/oauth2/rfc6749/errors.py", line 405, in raise_from_error
raise cls(**kwargs)
oauthlib.oauth2.rfc6749.errors.InvalidClientIdError: (invalid_request) Value passed for the token was invalid.