We not too long ago launched OAuth 2.0 Authorization Code Circulation with PKCE to be used with most of our v2 endpoints. As a backend-focused Python developer, I struggled with the circulation since a lot of the code I like to write down focuses on automation duties.
This tutorial will stroll you thru vital ideas associated to refresh tokens utilizing v2 of the Twitter API. In the event you don’t have already got entry to the Twitter API, you may join an account. Additionally, you will have to have OAuth 2.0 turned on in your App’s settings.
Tokens are solely legitimate for 2 hours
I used to be used to working with OAuth 1.0a, the place keys and tokens can be found to be used till they’re revoked. This isn’t the case with OAuth 2.0 Authorization Code Circulation with PKCE. Entry Tokens generated utilizing this circulation are solely legitimate for two hours.
Refresh tokens
Contained in the token object generated from the consent circulation is a refresh token. A refresh token permits an utility to acquire a brand new entry token with out prompting the person to log in once more.
To generate a refresh token, you need to set a scope for offline entry. If I used to be utilizing the handle Tweets endpoint and I wished to Tweet on behalf of a person each six months, I’d use the next line of Python code:
scopes = ["tweet.read", "users.read", "tweet.write", "offline.access"]
How lengthy are refresh tokens legitimate for?
Refresh tokens keep legitimate for six months, so you’ll want to refresh them a minimum of that usually or extra usually.
Producing tokens
To generate a token utilizing OAuth 2.0 Authorization Code Circulation with PKCE you should use a way just like this instance that permits you to search for an authenticated person’s bookmarks. Because the authenticated person might want to log in straight, and you will want to parse the response, I discovered making a Flask utility allowed for a extra automated course of.
The next code will generate a token and save the token right into a dictionary.
You’ll be working with the next libraries:
-
requests
for making HTTP requests -
requests_oauthlib
for working with OAuth 2.0 -
os
for parsing atmosphere variables and creating random strings -
re
,base64
andhashlib
to create the code problem and code verifier -
flask
for creating an online framework
In the event you don’t have already got flask, requests_oauthlib and requests put in you will want to put in these libraries.
You’ll first have to import the next libraries:
import base64
import hashlib
import os
import re
import requests
from requests_oauthlib import OAuth2Session
from flask import Flask, request, redirect, session, url_for
First, you will want to set a variable in your app
, which is the beginning of each Flask app. Moreover, you will want to set a secret key in your app to be a random string.
app = Flask(__name__)
app.secret_key = os.urandom(50)
The 2 primary credentials you will want to authenticate with OAuth 2.0 Authorization Code Circulation with PKCE are Consumer ID and Consumer Secret. You possibly can set these as atmosphere variables to make sure safety.
client_id = os.environ.get("CLIENT_ID")
client_secret = os.environ.get("CLIENT_SECRET")
Additionally, you will have to set a variable in your redirect URL, this must be the identical worth as your callback URL in your App’s settings within the Developer Portal.
redirect_uri = os.environ.get("REDIRECT_URI")
auth_url = "https://twitter.com/i/oauth2/authorize"
token_url = "https://api.twitter.com/2/oauth2/token"
To outline the permissions of your App, you will want to set the scopes of your utility. Try the authentication mapping information to find out what scopes you will want primarily based on the endpoints you’re utilizing. The scope offline.entry
permits you to generate refresh tokens. The scopes for this demo are tweet.learn
and customers.learn
, which supplies you entry to learn Tweets and acquire details about customers.
scopes = ["tweet.read", "users.read", "offline.access"]
You have to to set a code verifier which is a safe random string. The code verifier is used to create the code problem.
code_verifier = base64.urlsafe_b64encode(os.urandom(30)).decode("utf-8")
code_verifier = re.sub("[^a-zA-Z0-9]+", "", code_verifier
With PKCE the code problem is a base64 encoded string of the SHA256 hash of the code verifier.
code_challenge = hashlib.sha256(code_verifier.encode("utf-8")).digest()
code_challenge = base64.urlsafe_b64encode(code_challenge).decode("utf-8")
code_challenge = code_challenge.exchange("=", "")
Now you can begin with making a login web page that would be the first web page you’ll go to if you run your utility. @app.route("https://dev.to/")
signifies it’s the primary touchdown web page. This web page would be the web page that an authenticated person logs into.
@app.route("https://dev.to/")
def demo():
world twitter
twitter = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=scopes)
authorization_url, state = twitter.authorization_url(
auth_url, code_challenge=code_challenge, code_challenge_method="S256"
)
session["oauth_state"] = state
return redirect(authorization_url)
After the person logs in, they are going to be directed to the callback. Within the callback you’ll generate an object known as token
that comprises a sequence of tokens that features an entry token and a refresh token.
@app.route("/oauth/callback", strategies=["GET"])
def callback():
code = request.args.get("code")
token = twitter.fetch_token(
token_url=token_url,
client_secret=client_secret,
code_verifier=code_verifier,
code=code,
)
Now that you simply’ve generated a token object, now you can make a request to the authenticated person lookup, to acquire a person ID that can be utilized to entry lots of our v2 Customers endpoints resembling handle Tweets or handle blocks.
The access_token
variable within the token object is the bearer token you’d use to hook up with any of the endpoints that assist OAuth 2.0 Authorization Code Circulation with PKCE.
user_me = requests.request(
"GET",
"https://api.twitter.com/2/customers/me",
headers={"Authorization": "Bearer {}".format(token["access_token"])},
).json()
print(user_me)
user_id = user_me["data"]["id"]
Now that you simply’ve created a token and saved right into a dictionary now you can entry the token dictionary and create a refreshed token by means of this course of. This code must be added to your callback technique. This refreshed_token
will comprise a brand new entry token as properly.
tokens = {"new_token": token}
t = tokens["new_token"]
refreshed_token = twitter.refresh_token(
client_id=client_id,
client_secret=client_secret,
token_url=token_url,
refresh_token=t["refresh_token"],
)
tokens.replace({"new_token": refreshed_token})
return "You need to now have a refreshed token"
if __name__ == "__main__":
app.run()
Full code
Right here is the total code which you can save as app.py
import base64
import hashlib
import os
import re
import requests
from requests_oauthlib import OAuth2Session
from flask import Flask, request, redirect, session, url_for
app = Flask(__name__)
app.secret_key = os.urandom(50)
client_id = os.environ.get("CLIENT_ID")
client_secret = os.environ.get("CLIENT_SECRET")
redirect_uri = os.environ.get("REDIRECT_URI")
auth_url = "https://twitter.com/i/oauth2/authorize"
token_url = "https://api.twitter.com/2/oauth2/token"
scopes = ["tweet.read", "users.read", "offline.access"]
code_verifier = base64.urlsafe_b64encode(os.urandom(30)).decode("utf-8")
code_verifier = re.sub("[^a-zA-Z0-9]+", "", code_verifier)
code_challenge = hashlib.sha256(code_verifier.encode("utf-8")).digest()
code_challenge = base64.urlsafe_b64encode(code_challenge).decode("utf-8")
code_challenge = code_challenge.exchange("=", "")
@app.route("https://dev.to/")
def demo():
world twitter
twitter = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=scopes)
authorization_url, state = twitter.authorization_url(
auth_url, code_challenge=code_challenge, code_challenge_method="S256"
)
session["oauth_state"] = state
return redirect(authorization_url)
@app.route("/oauth/callback", strategies=["GET"])
def callback():
code = request.args.get("code")
token = twitter.fetch_token(
token_url=token_url,
client_secret=client_secret,
code_verifier=code_verifier,
code=code,
)
user_me = requests.request(
"GET",
"https://api.twitter.com/2/customers/me",
headers={"Authorization": "Bearer {}".format(token["access_token"])},
).json()
print(user_me)
user_id = user_me["data"]["id"]
tokens = {"new_token": token}
t = tokens["new_token"]
refreshed_token = twitter.refresh_token(
client_id=client_id,
client_secret=client_secret,
token_url=token_url,
refresh_token=t["refresh_token"],
)
tokens.replace({"new_token": refreshed_token})
return "You need to now have a refreshed token"
if __name__ == "__main__":
app.run()
To run the file domestically you may run the next line:
python app.py
Subsequent steps
Hopefully, this is usually a place to begin so that you can get began with producing refresh tokens. As a subsequent step, if you’re utilizing Flask you could wish to think about using a schedular to replace your refresh tokens usually in an automatic vogue. Moreover you could wish to contemplate saving your tokens to a database in a safe vogue. This code pattern will also be prolonged to permit you to hook up with any of the endpoints that assist v2 and may be deployed to a server as a part of a extra full utility.
Make sure to tell us on the boards in case you run into any troubles alongside the best way, or Tweet us at @TwitterDev if this tutorial evokes you to create something.