def on_refresh_complete(cls, response, id, callback): """Callback for request to get a new access token based on refresh token.""" if response.code in (400, 401): if 'invalid_grant' in response.body: # Our refresh token is invalid, which means that we don't have # permission to access this user's content anymore. Forget them. Cache.delete(cls.auth_cache_key_template % id) Cache.delete(cls.profile_cache_key_template % id) TokenIdMapping.remove_id(id) logging.error("Access was revoked for %s; cached data deleted.", id) logging.error("HTTP %s while trying to refresh access token for %s.", response.code, id) return IOLoop.instance().add_callback(lambda: callback(None)) elif response.code != 200: logging.error("Non-200 response to refresh token request (%s, id=%s): %r" % (response.code, id, response.body)) return IOLoop.instance().add_callback(lambda: callback(None)) results = json.loads(response.body) # sanity check if results['token_type'] != "Bearer": logging.error('Unknown token type received: %s' % results['token_type']) return IOLoop.instance().add_callback(lambda: callback(None)) token = results['access_token'] Cache.set(cls.auth_cache_key_template % id, token, time=results['expires_in']) IOLoop.instance().add_callback(lambda: callback(token))
def on_profile_request_complete(self, person): """Callback for the initial OAuth flow's call to fetch_person_by_token.""" # We compute the time= param here to take into account potential time # spent during the API call. Cache.set(self.auth_cache_key_template % person['id'], self.gplus_access_token, time=int((self.gplus_expires_at - datetime.datetime.today()).total_seconds()), ) # store refresh token and gplus user id in database if self.gplus_refresh_token is not None: TokenIdMapping.update_refresh_token(person['id'], self.gplus_refresh_token) self.set_cookie('gplus_id', str(person['id'])) self.redirect('/')
def access_token_for_id(cls, id, callback): """Returns the access token for an id, acquiring a new one if necessary.""" token = Cache.get(cls.auth_cache_key_template % id) if token: return IOLoop.instance().add_callback(lambda: callback(token)) # If we don't have an access token cached, see if we have a refresh token token = TokenIdMapping.lookup_refresh_token(id) if token: post_body = urllib.urlencode({ 'client_id': Config.get('oauth', 'client-id'), 'client_secret': Config.get('oauth', 'client-secret'), 'refresh_token': token, 'grant_type': 'refresh_token', }) http_client = AsyncHTTPClient() return http_client.fetch( 'https://accounts.google.com/o/oauth2/token', lambda response: cls.on_refresh_complete(response, id, callback), method='POST', body=post_body, request_timeout=20.0, connect_timeout=15.0, ) else: logging.error("Unable to update access token for %s, no refresh token stored.", id) return IOLoop.instance().add_callback(lambda: callback(None))
def get(self): gplus_id = self.get_cookie('gplus_id') if gplus_id: # If we lost rights, but someone still has the cookie, get rid of it. if not TokenIdMapping.lookup_refresh_token(gplus_id): return self.redirect('/clear') self.render('authed_main.html', gplus_id=gplus_id, feed_url="http://%s/atom/%s" % (self.request.host, gplus_id), ) else: self.render('main.html')