Some time ago I wrote a class for myself to handle OAuth2 authentication with Google APIs. It might serve as an example for you. And, yes, you need to register an "application", but that is just to get the client id/secret.
Some notes:
The class uses the 'offline' access type to obtain credentials that can be stored and re-used in the future.
The settings
variable holds an instance of a class storing all my settings, in this case, the previously obtained google api credentials.
GAuthDialog
is a dialog that presents the user with user/password login and reads the code google produces.
The execute
method wraps any method that requires access to the API and authentication.
The class can be used as follows, e.g. for google drive:
self._gapi = GApi(settings, 'https://www.googleapis.com/auth/drive.readonly', 'drive', 'v2')
self._gapi.execute(self.get_file_list)
and then we have:
def get_file_list(self):
query="query"
children = self._gapi.service.files().list(q=query).execute()
And here comes the code of the class:
from oauth2client.client import OAuth2WebServerFlow, Credentials, AccessTokenRefreshError
from apiclient.discovery import build
from googleapiclient.errors import HttpError
import httplib2
class GApi():
class CredentialsError(Exception):
pass
# App credentials from developers console
__client_id = ''
__client_secret = ''
# Redirect URI for installed (non-web) apps
__redirect_uri = 'urn:ietf:wg:oauth:2.0:oob'
def __init__(self, settings, scopes, service_name, version):
self.__settings = settings
self.__scopes = scopes
self.__service_name = service_name
self.__version = version
self.__service = None
self.__credentials = None
# Try restoring credentials from settings
if self.__settings.get_gapi_credentials(self.__service_name):
self.__credentials = Credentials.new_from_json(
self.__settings.get_gapi_credentials(self.__service_name))
@property
def service(self):
return self.__service
def execute(self, method, *args, **kwargs):
self.__setup()
try:
return method(*args, **kwargs)
except AccessTokenRefreshError:
pass # Will re-authenticate below
except HttpError as err:
# Rethrow since HttpError has a bug in str()
raise Exception("Response: %s, Content: %s" %
(str(err.resp), str(err.content)))
# Try re-authenticating
self.__reauthenticate()
try:
return method(**kwargs)
except HttpError as err:
# Rethrow since HttpError has a bug in str()
raise Exception("Response: %s, Content: %s" %
(str(err.resp), str(err.content)))
def __obtain_credentials(self):
# Initialize the flow
flow = OAuth2WebServerFlow(self.__client_id, self.__client_secret,
self.__scopes, redirect_uri=self.__redirect_uri)
flow.params['access_type'] = 'offline'
# Run through the OAuth flow and retrieve credentials
uri = flow.step1_get_authorize_url()
# Get code from dialog
dialog = GAuthDialog(uri)
if dialog.exec() == QtWidgets.QDialog.Accepted and dialog.auth_code:
# Get the new credentials
self.__credentials = flow.step2_exchange(dialog.auth_code)
# Set them in settings
self.__settings.set_gapi_credentials(
self.__service_name, self.__credentials.to_json())
else:
self.__credentials = None
self.__settings.set_gapi_credentials(self.__service_name, None)
def __reauthenticate(self):
self.__credentials = None
self.__service = None
self.__setup()
def __setup(self):
# Do we have credentials?
if not self.__credentials:
self.__obtain_credentials()
# Check if we got credentials
if self.__credentials:
# Do we have service?
if not self.__service:
# Create an httplib2.Http object and authorize it with our credentials
http = httplib2.Http()
http = self.__credentials.authorize(http)
self.__service = build(self.__service_name,
self.__version, http=http)
else:
raise GApi.CredentialsError