Skip to content

Instantly share code, notes, and snippets.

@anderson-marques
Created March 11, 2021 17:42
Show Gist options
  • Select an option

  • Save anderson-marques/bb86adfccf7ddb9cf6a74331053fddcf to your computer and use it in GitHub Desktop.

Select an option

Save anderson-marques/bb86adfccf7ddb9cf6a74331053fddcf to your computer and use it in GitHub Desktop.
oauth2_device_flow.py
"""
OAuth2 Device Flow adaptation from Implicit Flow - Useful for CLIs
"""
from http.server import SimpleHTTPRequestHandler, HTTPServer
import os
from os.path import expanduser
import json
callback_html = """
<body style="font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif">
<script>
let originalHash = window.location.hash;
window.location.hash = '';
let accessToken;
if (originalHash.split('#').length == 2) {
for (var param of originalHash.split('#')[1].split('&')){
let paramName = param.split('=')[0]
let paramValue = param.split('=')[1]
if (paramName === 'access_token'){
accessToken = paramValue;
}
}
}
if (accessToken !== undefined) {
let title = document.createElement('h4');
title.textContent = 'Copy the device code and paste in the terminal:';
let deviceCode = document.createElement('p');
deviceCode.textContent = accessToken;
document.body.appendChild(title);
document.body.appendChild(deviceCode);
} else {
let title = document.createElement('h4');
title.textContent = 'Not autenticated!'
document.body.appendChild(title);
}
</script>
</body>
"""
config_folder_name = 'device_flow'
config_file_name = 'config'
class OAuth2CallbackHandler( SimpleHTTPRequestHandler ):
def do_GET(self):
if (self.path == '/cb'):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.send_header("Content-Length", str(len(callback_html)))
self.end_headers()
self.wfile.write(callback_html.encode('utf-8'))
access_token = input("Enter the code value: ")
home = expanduser("~")
config_path = f'{home}/.{config_folder_name}'
file_path = f"{config_path}/{config_file_name}.json"
if not os.path.exists(config_path):
os.makedirs(config_path)
f = open(file_path, "a")
config = { "access_token": f'{access_token}' }
f.write(json.dumps(config))
f.close()
self.server.server_close()
print("\nUser authenticated!")
exit(0)
def login(config={}):
base_url = config['base_url']
client_id = config['client_id']
redirect_uri = config['redirect_uri']
state = config['state']
scope = config['scope']
port = config['port'] if 'port' in config.keys() else 4321
if 'folder_name' in config.keys():
global config_folder_name
config_folder_name = config['folder_name']
if 'file_name' in config.keys():
global config_file_name
config_file_name = config['file_name']
login_url = f'{base_url}?client_id={client_id}&redirect_uri={redirect_uri}&response_type=token&state={state}&scope={scope}'
print(f'\nCopy and paste this in your browser: \n\n\t{login_url}')
httpd = HTTPServer(('', port), OAuth2CallbackHandler)
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass
httpd.server_close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment