Last active
May 16, 2023 14:52
-
-
Save lordjabez/d3a3e7be78284c934f988fd57c1cbcb5 to your computer and use it in GitHub Desktop.
Get an OAuth2 access token with Python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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