I'm trying to use the Google Slides API on Google App Engine, and despite using the Google code samples (specifically for OAuth2 & the Slides API on App Engine), I'm running into problems.
Here is my App Engine code, with unnecessary cruft removed (everything's in main.app). What I'm doing is trying to posting a string from an HTML form and then build a blank presentation. I've already used the Slides API with a simple script that I prototyped; I'm now trying to make this self-serve via an App Engine app, but it's the change in authentication that's tripping me up.
from googleapiclient import discovery
from oauth2client import client
from oauth2client.contrib import appengine
from google.appengine.api import memcache
CLIENT_SECRETS = os.path.join(os.path.dirname(__file__), 'client_secrets.json')
MISSING_CLIENT_SECRETS_MESSAGE = """[omitted]""" % CLIENT_SECRETS
http = httplib2.Http()
service = discovery.build('slides', 'v1', http=http)
decorator = appengine.OAuth2DecoratorFromClientSecrets(
CLIENT_SECRETS,
scope='https://www.googleapis.com/auth/presentations https://www.googleapis.com/auth/drive',
message=MISSING_CLIENT_SECRETS_MESSAGE)
class SlideBuilder(webapp2.RequestHandler):
@decorator.oauth_required
def post(self):
programslug = self.request.get('programid')
presoname = str(programslug) + ' Mentors'
presentationbody = {
'title': presoname
}
presentation = service.presentations().create(body=presentationbody).execute()
I want to point out that I downloaded the most recent client_secrets.json directly from the API console, so that should match up correctly for CLIENT_SECRETS.
The error I'm getting (on dev server; but it's also on the live app) is this:
Traceback (most recent call last):
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1535, in __call__
rv = self.handle_exception(request, response, e)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1529, in __call__
rv = self.router.dispatch(request, response)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1278, in default_dispatcher
return route.handler_adapter(request, response)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1102, in __call__
return handler.dispatch()
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 572, in dispatch
return self.handle_exception(e, self.app.debug)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 570, in dispatch
return method(*args, **kwargs)
File "/Users/jedc/pm-tools/oauth2client/contrib/appengine.py", line 644, in check_oauth
resp = method(request_handler, *args, **kwargs)
File "/Users/jedc/pm-tools/main.py", line 113, in post
presentation = service.presentations().create(body=presentationbody).execute()
File "/Users/jedc/pm-tools/oauth2client/_helpers.py", line 133, in positional_wrapper
return wrapped(*args, **kwargs)
File "/Users/jedc/pm-tools/googleapiclient/http.py", line 840, in execute
raise HttpError(resp, content, uri=self.uri)
HttpError: <HttpError 401 when requesting https://slides.googleapis.com/v1/presentations?alt=json returned "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.">
It feels like there's something subtle but dumb that I'm doing here. I'd appreciate any help or pointers to figure out what that is!