How to implement Twitter's OAuth2 (Python) The writeup I wish existed before I tried to implement it. tweepy and python-twitter do not support OAuth2 on Twitter properly. And the Twitter documentation seems to lack a lot.
- Goto https://developer.twitter.com/en/portal
- create a new project
- get a twitter oauth client id (under user authentication settings)
- get a twitter oauth client secret (under user authentication settings)
- Setup the User Authentication Settings -- be sure to setup your local and production callback urls (ie: http://127.0.0.1:8080/callback and https://production.com/callback)
Example user flow:
- Present user with a 'authenticate with twitter' link
- user clicks the link which opens twitter's oauth2 approval screen
- user logs in to the twitter screen
- twitter redirects the user back to your /callback url
- you save the authentication token and start interacting with the user's account
- start by making a random string that will only be used for this one request
rand_string = "".join(random.choices(string.ascii_uppercase + string.ascii_lowercase + string.digits, k=32))
- then, build the url
url = f'https://twitter.com/i/oauth2/authorize' + \
'?response_type=code' + \
f'&client_id={twitter_client_id}' + \
f'&redirect_uri={callback_uri}&scope=tweet.read+users.read' + \
f'&state={session_id}' + \
f'&code_challenge={rand_string}'+ \
'&code_challenge_method=plain'
- session_id: you need to track your user so you know who it is when they are redirected to your /callback
- twitter_client_id: the client id from twitter
- callback_uri: where you want twitter to send the user after they login. ** see note about CALLBACK_URI below **
In this step, Twitter wants a url encoded callback uri. So, don't submit: https://127.0.0.1:8080/callback.
Do submit: https%3A%2F%2F127.0.0.1%3A8080%2Fcallback
Using variables from the /callback url, send a request to twitter to get the access_token
# parse variables from the url
r = {}
r['access_code'] = request.args.get('code')
r['response_url'] = request.url
# contruct the basic auth header client_id:client_secret base64 encoded
message = twitter_client_id+":"+twitter_client_secret
message_bytes = message.encode('ascii')
base64_bytes = base64.b64encode(message_bytes)
base64_message = base64_bytes.decode('ascii')
r['base64_message'] = base64_message
# Get the access token from twitter
my_header = {}
my_header['Content-Type'] = 'application/x-www-form-urlencoded'
my_header['Authorization'] = 'Basic ' + base64_message
my_data = {}
my_data['code'] = r['access_code']
my_data['grant_type'] = 'authorization_code'
my_data['redirect_uri'] = 'http://127.0.0.1:8080/callback' # NO need to url encode this callback_uri
my_data['code_verifier'] = session['twitter_code_challenge']
my_data['code_challenge_method'] = session['twitter_code_challenge_method']
url = 'https://api.twitter.com/2/oauth2/token'
x = requests.post(url, headers=my_header, data=my_data)
y = x.json()
r['access_token'] = y['access_token']
** Save the access_token for the user **
Let's get some info about the user
# get info about the user
url = "https://api.twitter.com/2/users/me?" + \
"user.fields=created_at,description,entities,id,location,name,pinned_tweet_id,profile_image_url,protected,public_metrics,url,username,verified,withheld"
my_header = {}
my_header["Authorization"] = "Bearer " + r['access_token']
x = requests.get(url, headers=my_header)
r['twitter_user_detail'] = x.json()
r['this_twitter_user'] = r['twitter_user_detail']['data']['id']
r['twitter_username'] = r['twitter_user_detail']['data']['username']
r['twitter_follower_count'] = r['twitter_user_detail']['data']['public_metrics']['followers_count']
r['twitter_following_count'] = r['twitter_user_detail']['data']['public_metrics']['following_count']
r['twitter_tweet_count'] = r['twitter_user_detail']['data']['public_metrics']['tweet_count']
You will need to periodically refresh the access_token if you want to continue processing requests without user interaction.
[coming soon]