I'm not saying it's pretty - it's not. This code is ugly as sin, but it works using GAE, Webapp2 and urllib2, rather than other frameworks/libraries.
import os, sys, cgi, json, cookielib
sys.path.append("lib")
import jinja2, webapp2, urllib, urllib2
from google.appengine.api import users, oauth, urlfetch
from webapp2_extras import sessions
JINJA_ENVIRONMENT = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
extensions=['jinja2.ext.autoescape'],
autoescape=True)
class BaseHandler(webapp2.RequestHandler):
def dispatch(self):
# Get a session store for this request.
self.session_store = sessions.get_store(request=self.request)
try:
# Dispatch the request.
webapp2.RequestHandler.dispatch(self)
finally:
# Save all sessions.
self.session_store.save_sessions(self.response)
@webapp2.cached_property
def session(self):
# Returns a session using the default cookie key.
return self.session_store.get_session()
class ConsoleLogin(BaseHandler):
def get(self):
# Set variables to avoid problems later
code = ''
url = ''
access_token = ''
scope = ''
username = ''
google_user = users.get_current_user()
if google_user:
url = self.request.url
if ('code' not in url and not self.session.get('access_token')):
# First time user coming to site. Redirect to GH for code
url = 'https://github.com/login/oauth/authorize?scope=user,repo&client_id=' + os.environ.get('CLIENT_ID')
self.redirect(url)
elif 'code' in url:
# User has been to GH, continue with auth process
code = url.replace('http://localhost:8080/?code=', '')
# We have code, now get Access Token
fields = {
"client_id" : os.environ.get('CLIENT_ID'),
"client_secret" : os.environ.get('CLIENT_SECRET'),
"code" : code
}
url = 'https://github.com/login/oauth/access_token'
data = urllib.urlencode(fields)
result = urlfetch.fetch(url=url,
payload=data,
method=urlfetch.POST
)
# Get the query string
query_string = str(result.content)
# Get the access token out of the full query string
access_token = query_string[13:]
end_access = access_token.find('&')
access_token = access_token[:end_access]
# Get the scope out of the full query string
start_scope = query_string.find('scope')
end_scope = query_string.find('token_type')
start_scope = start_scope + 6 # remove the word 'scope='
end_scope = end_scope - 1 # remove the & symobol
scope = query_string[start_scope:end_scope]
scope = scope.split('%2C')
# Store the Access Token in a Session Variable
self.session['access_token'] = access_token
self.session['scope'] = scope
# And redirect to the base URL for neatness and to avoid other issues
self.redirect('/')
access_token = self.session.get('access_token')
scope = self.session.get('scope')
context = {
'access_token' : access_token,
'scope' : scope,
'username' : username,
}
# Template Settings
temp = 'templates/index.html'
template = JINJA_ENVIRONMENT.get_template(temp)
self.response.write(template.render(context))
config = {}
config['webapp2_extras.sessions'] = {
'secret_key': 'the-beatles-will-always-rule',
}
application = webapp2.WSGIApplication([
('/', ConsoleLogin),
], debug=True, config=config)