Source code for oauth_dropins.google_signin

"""Google Sign-In OAuth drop-in.

Google Sign-In API docs:
Python API client docs:
requests-oauthlib docs:
import logging

from flask import request
from import ndb
from requests_oauthlib import OAuth2Session

from . import views, models
from .webutil import flask_util, util
from .webutil.util import json_dumps, json_loads

logger = logging.getLogger(__name__)

GOOGLE_CLIENT_ID ='google_client_id')
GOOGLE_CLIENT_SECRET ='google_client_secret')
# Discovered on 1/30/2019 from:
# Background:

[docs]class GoogleUser(models.BaseAuth): """An authenticated Google user. Provides methods that return information about this user and make OAuth-signed requests to Google APIs. Stores OAuth credentials in the datastore. See models.BaseAuth for usage details. To make Google API calls: """ user_json = ndb.TextProperty() token_json = ndb.TextProperty()
[docs] def site_name(self): return 'Google'
[docs] def user_display_name(self): """Returns the user's name.""" return json_loads(self.user_json).get('name') or 'unknown'
[docs] def access_token(self): """Returns the OAuth access token string.""" return json_loads(self.token_json)['access_token']
class Scopes(object): # OAuth/OpenID Connect scopes: # # Google scopes: # DEFAULT_SCOPE = 'openid' SCOPE_SEPARATOR = ' '
[docs]class Start(Scopes, views.Start): """Starts the OAuth flow.""" NAME = 'google_signin' LABEL = 'Google' """""" INCLUDE_GRANTED_SCOPES = True
[docs] def redirect_url(self, state=None): assert GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET, \ "Please fill in the google_client_id and google_client_secret files in your app's root directory." session = OAuth2Session(GOOGLE_CLIENT_ID, scope=self.scope, redirect_uri=self.to_url()) auth_url, state = session.authorization_url( AUTH_CODE_URL, state=state, # ask for a refresh token so we can get an access token offline access_type='offline', prompt='consent', # include_granted_scopes=self.INCLUDE_GRANTED_SCOPES) return auth_url
[docs]class Callback(Scopes, views.Callback): """Finishes the OAuth flow."""
[docs] def dispatch_request(self): # handle errors state = request.values.get('state') error = request.values.get('error') desc = request.values.get('error_description') if error: msg = f'Error: {error}: {desc}' if error == 'access_denied': return self.finish(None, state=state) else: flask_util.error(msg) # extract auth code and request access token session = OAuth2Session(GOOGLE_CLIENT_ID, scope=self.scope, redirect_uri=request.base_url) session.fetch_token(ACCESS_TOKEN_URL, client_secret=GOOGLE_CLIENT_SECRET, authorization_response=request.url) # get OpenID Connect user info # resp = session.get(OPENID_CONNECT_USERINFO) try: resp.raise_for_status() except BaseException as e: util.interpret_http_exception(e) raise user_json = json_loads(resp.text)'Got one person', user_json) user = GoogleUser(id=user_json['sub'], user_json=json_dumps(user_json), token_json=json_dumps(session.token)) user.put() return self.finish(user, state=state)