Skip to content

Instantly share code, notes, and snippets.

@CarlFK
Created May 16, 2023 01:05
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CarlFK/85a16238366528a1b5750e57cbddad02 to your computer and use it in GitHub Desktop.
Save CarlFK/85a16238366528a1b5750e57cbddad02 to your computer and use it in GitHub Desktop.
my first webserver
# veyepar/dj/googauth/utils.py
import argparse
import json
import os
from http.server import HTTPServer, BaseHTTPRequestHandler
from pprint import pprint
from urllib.parse import urlparse, parse_qs
import google.oauth2.credentials
import google_auth_oauthlib.flow
import googleapiclient.discovery
# REDIRECT_URL = settings.GOOG_REDIRECT_URL # 'http://127.0.0.1:8000/googauth/redirect/'
"""
Users will be redirected to this path after they have authenticated with Google.
The path will be appended with the authorization code for access, and must have a protocol.
It can’t contain URL fragments, relative paths, or wildcards, and can’t be a public IP address.
"""
def goog_start( client_secret_file, scopes, redirect_uri ):
# Construct a URL that will ask the user to give this app permission to scopes
# Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps.
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
client_secret_file,
scopes=scopes)
# The URI created here must exactly match one of the authorized redirect URIs
# for the OAuth 2.0 client, which you configured in the API Console. If this
# value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch'
# error.
flow.redirect_uri = redirect_uri
authorization_url, state = flow.authorization_url(
# Enable offline access so that you can refresh an access token without
# re-prompting the user for permission.
access_type='offline',
)
# Don't enable incremental authorization.
# This will cause a "Warning: Scope Changed" error later.
# If someday we need to manage more than one set of scopes
# then we well come back here.
# include_granted_scopes='true',
return authorization_url
def goog_token( client_secret_file, scopes, redirect_uri, authorization_response, state):
# Google redirects the local browser to a url on the local server
# parse the URL and send the needed parameters here.
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
client_secret_file,
scopes=scopes,
state=state)
flow.redirect_uri = redirect_uri
# Use the authorization server's response to derive? the OAuth 2.0 tokens.
flow.fetch_token(authorization_response=authorization_response)
credentials = flow.credentials
credd = {'token': credentials.token,
'refresh_token': credentials.refresh_token,
'token_uri': credentials.token_uri,
}
return credd
def get_items(api_service_name, api_version, credd):
# verify we can do something with the token
service = googleapiclient.discovery.build(
api_service_name, api_version, credentials=credentials)
request = service.videos().list(
part="id",
chart="mostPopular",
prettyPrint=True
)
response = request.execute()
if not response['items']:
print('No data found.')
d = {"message": "No data found or user credentials invalid."}
else:
d = {"items": response['items']}
return d
def get_attribs(o):
# sus out the interesting attributes
d={}
for k in dir(o):
if not k.startswith("_") and not callable(getattr(o,k)):
d[k] = getattr(o,k)
return d
class My_Handler(BaseHTTPRequestHandler):
redirect_url=None
def do_GET(self):
d = get_attribs(self)
# pprint(d)
if self.path == '/':
self.send_response(301)
content = f"redirecting to {self.redirect_url=}"
self.send_header('Location', self.redirect_url)
else:
parsed = urlparse(self.path)
qs = parse_qs(parsed.query)
self.send_response(200)
self.send_header('Content-type', 'application/json')
content = json.dumps([parsed,qs], indent=2)
self.end_headers()
self.wfile.write(bytes(content, 'utf-8'))
def wait_for_callback( client_secret_file, scopes, redirect_url ):
# run a little webserver,
# wait for the callback
# get the token and things from the URL
My_Handler.redirect_url=redirect_url
print("wating for a connection...")
httpd = HTTPServer(('localhost', 8080), My_Handler)
o = httpd.handle_request()
d = get_attribs(o)
pprint(d)
d = get_attribs(httpd)
# pprint(d)
# state = request.GET['state']
return {}
def goog_token( client_secret_file, scopes, redirect_uri, authorization_response, state):
credd = Web_Server.credd
return credd
def get_args():
parser = argparse.ArgumentParser(
description="Get a token from google.",
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument('-client-secret-file', '-c',
default=os.path.expanduser('~/.creds/client_secret.json'),
dest="client_secret_file",
help="Process API key (what needs access to upload.)"),
parser.add_argument('--token-file', '-t',
default=os.path.expanduser('~/.creds/oauth_token.json'),
help="oAuth token file. (permission from the destination account owner)")
parser.add_argument('--scope', '-s',
nargs='+',
dest="scopes",
default='https://www.googleapis.com/auth/youtube.readonly',
help="oAuth token file. (permission from the destination account owner)")
parser.add_argument('--redirect-url', '-r',
default='http://localhost:8080/redirect/',
help="The URL google will redirect to once the user allow/denys access.")
parser.add_argument('--oauthlib-insecure-transport', '-i',
default=True,
help='set OAUTHLIB_INSECURE_TRANSPORT = 1 for runing on http://localhost:8080' )
args = parser.parse_args()
return args
def main():
args = get_args()
credd = wait_for_callback( args.client_secret_file, args.scopes, args.redirect_url )
pprint(credd)
return
if args.oauthlib_insecure_transport:
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
# oAuth2 step 1
start_url = goog_start( args.client_secret_file, args.scopes, args.redirect_url )
print( f"Browse to {start_url}" )
# oAuth2 step 2
credd = wait_for_callback( args.client_secret_file, args.scopes )
# bonus step to prove it worked:
d = get_items(api_service_name="youtube", api_version="v3", credd=credd)
pprint(d)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment