def get_access_token_for_id(gplus_id): """Get an access token for an id, potentially via refresh token if necessary.""" # Check the cache first. token = Cache.get(ACCESS_TOKEN_CACHE_KEY_TEMPLATE % gplus_id) if token: return token # If we don't have a cached token, see if we have a refresh token available. refresh_token = TokenIdMapping.lookup_refresh_token(gplus_id) if not refresh_token: raise UnavailableException( 'No tokens available for G+ id %s.' % gplus_id, 401) data = { 'client_id': Config.get('oauth', 'client-id'), 'client_secret': Config.get('oauth', 'client-secret'), 'refresh_token': refresh_token, 'grant_type': 'refresh_token', } try: response = session.post(OAUTH2_BASE + '/token', data=data, timeout=GOOGLE_API_TIMEOUT) result = response.json() except requests.exceptions.Timeout: raise UnavailableException('Access token API request timed out.', 504) except Exception as e: raise UnavailableException( 'Access token API request raised exception "%r".' % e, 502) if 'invalid_grant' in result: # The provided refresh token is invalid which means the user has revoked # access to their content - thus, pluss should forget about them. Cache.delete(ACCESS_TOKEN_CACHE_KEY_TEMPLATE % gplus_id) Cache.delete(PROFILE_CACHE_KEY_TEMPLATE % gplus_id) TokenIdMapping.remove_id(gplus_id) raise UnvailableException('Access revoked for G+ id %s.' % gplus_id) elif response.status_code != 200: app.logger.error( 'Non-200 response to access token refresh request (%s): "%r".', response.status_code, result) raise UnavailableException( 'Failed to refresh access token for G+ id %s.' % gplus_id, 502) elif result.get('token_type') != 'Bearer': app.logger.error('Unknown token type "%s" refreshed for G+ id %s.', result.get('token_type'), gplus_id) raise UnavailableException( 'Failed to refresh access token for G+ id %s.' % gplus_id, 502) token = result['access_token'] Cache.set(ACCESS_TOKEN_CACHE_KEY_TEMPLATE % gplus_id, token, time=result['expires_in']) return token
def make_request(retry=True): token = get_access_token_for_id(gplus_id) request.headers['Authorization'] = 'Bearer %s' % token prepared_request = request.prepare() response = session.send(prepared_request, timeout=GOOGLE_API_TIMEOUT) if response.status_code == 401: # Our access token is invalid. If this is the first failure, # try forcing a refresh of the access token. if retry: Cache.delete(ACCESS_TOKEN_CACHE_KEY_TEMPLATE % gplus_id) return make_request(retry=False) return response
def get_access_token_for_id(gplus_id): """Get an access token for an id, potentially via refresh token if necessary.""" # Check the cache first. token = Cache.get(ACCESS_TOKEN_CACHE_KEY_TEMPLATE % gplus_id) if token: return token # If we don't have a cached token, see if we have a refresh token available. refresh_token = TokenIdMapping.lookup_refresh_token(gplus_id) if not refresh_token: raise UnavailableException('No tokens available for G+ id %s.' % gplus_id, 401) data = { 'client_id': Config.get('oauth', 'client-id'), 'client_secret': Config.get('oauth', 'client-secret'), 'refresh_token': refresh_token, 'grant_type': 'refresh_token', } try: response = session.post(OAUTH2_BASE + '/token', data=data, timeout=GOOGLE_API_TIMEOUT) result = response.json() except requests.exceptions.Timeout: raise UnavailableException('Access token API request timed out.', 504) except Exception as e: raise UnavailableException('Access token API request raised exception "%r".' % e, 502) if 'invalid_grant' in result or ('error' in result and result['error'] == 'invalid_grant'): # The provided refresh token is invalid which means the user has revoked # access to their content - thus, pluss should forget about them. Cache.delete(ACCESS_TOKEN_CACHE_KEY_TEMPLATE % gplus_id) Cache.delete(PROFILE_CACHE_KEY_TEMPLATE % gplus_id) TokenIdMapping.remove_id(gplus_id) raise UnavailableException('Access revoked for G+ id %s.' % gplus_id, 502) elif response.status_code != 200: app.logger.error('Non-200 response to access token refresh request (%s): "%r".', response.status_code, result) raise UnavailableException('Failed to refresh access token for G+ id %s.' % gplus_id, 502) elif result.get('token_type') != 'Bearer': app.logger.error('Unknown token type "%s" refreshed for G+ id %s.', result.get('token_type'), gplus_id) raise UnavailableException('Failed to refresh access token for G+ id %s.' % gplus_id, 502) token = result['access_token'] Cache.set(ACCESS_TOKEN_CACHE_KEY_TEMPLATE % gplus_id, token, time=result['expires_in']) return token