Skip to content

Instantly share code, notes, and snippets.

@lordjabez
Last active May 16, 2023 14:52
Show Gist options
  • Save lordjabez/d3a3e7be78284c934f988fd57c1cbcb5 to your computer and use it in GitHub Desktop.
Save lordjabez/d3a3e7be78284c934f988fd57c1cbcb5 to your computer and use it in GitHub Desktop.
Get an OAuth2 access token with Python
#!/usr/bin/env python3
# pip install beautifulsoup4 keyring pyjwt requests
# ./get-access-token.py $auth_domain $client_id $api_name $username
import getpass
import sys
import time
import urllib.parse
import bs4
import jwt
import keyring
import requests
auth_domain = sys.argv[1]
client_id = sys.argv[2]
api_name = sys.argv[3]
username = sys.argv[4]
authorize_url = f'https://{auth_domain}/authorize'
login_url = f'https://{auth_domain}/u/login'
token_url = f'https://{auth_domain}/oauth/token'
audience_url = f'https://{api_name}/api'
redirect_uri = 'http://localhost:3000'
session = requests.Session()
def load_access_token():
service = f'auth0.{client_id}'
return keyring.get_password(service, username)
def save_access_token(access_token):
service = f'auth0.{client_id}'
keyring.set_password(service, username, access_token)
def token_is_valid(access_token):
try:
decoded_token = jwt.decode(access_token, algorithms=['RS256'], options={'verify_signature': False})
expiration_timestamp = decoded_token['exp']
current_timestamp = time.time()
return expiration_timestamp > current_timestamp
except (jwt.exceptions.DecodeError, KeyError):
return False
def get_initial_state():
authorize_params = {
'client_id': client_id,
'audience': audience_url,
'scope': 'openid profile email',
'prompt': 'login',
'response_type': 'code',
'redirect_uri': redirect_uri,
}
authorize_response = session.get(authorize_url, params=authorize_params)
login_document = bs4.BeautifulSoup(authorize_response.text, 'html.parser')
state_input = login_document.find('input', attrs={'name': 'state'})
return state_input['value']
def get_authorization_code(state):
prompt = f'Enter password for {username}: '
password = getpass.getpass(prompt)
login_data = {
'state': state,
'username': username,
'password': password,
}
login_response = session.post(login_url, data=login_data, allow_redirects=False)
resume_location = login_response.headers['Location']
resume_url = f'https://{auth_domain}{resume_location}'
resume_response = session.get(resume_url, allow_redirects=False)
code_location = resume_response.headers['Location']
parsed_code_url = urllib.parse.urlparse(code_location)
return urllib.parse.parse_qs(parsed_code_url.query)['code'][0]
def get_access_token():
state = get_initial_state()
authorization_code = get_authorization_code(state)
token_data = {
'client_id': client_id,
'grant_type': 'authorization_code',
'code': authorization_code,
'redirect_uri': redirect_uri,
}
token_response = requests.post(token_url, data=token_data)
return token_response.json()['access_token']
access_token = load_access_token()
if not token_is_valid(access_token):
access_token = get_access_token()
save_access_token(access_token)
print(access_token)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment