Trouble with oauth2client.client.Storage

1.2k views Asked by At

I'm trying to use OAuth2 with my App Engine application, but I keep getting the following error:

Encountered unexpected error from ProtoRPC method implementation: IOError ([Errno 30] Read-only file system: 'credentials.dat')
Traceback (most recent call last):
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/protorpc-1.0/protorpc/wsgi/service.py", line 181, in protorpc_service_app
    response = method(instance, request)
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/endpoints-1.0/endpoints/api_config.py", line 1332, in invoke_remote
    return remote_method(service_instance, request)
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/protorpc-1.0/protorpc/remote.py", line 412, in invoke_remote_method
    response = method(service_instance, request)
  File "/base/data/home/apps/s~art-everywhere/7.385356767964097452/main.py", line 438, in upload_putphoto
    gd_client = PicasaWA.login()
  File "/base/data/home/apps/s~art-everywhere/7.385356767964097452/main.py", line 1653, in login
    storage.put(credentials)
  File "/base/data/home/apps/s~art-everywhere/7.385356767964097452/oauth2client/client.py", line 325, in put
    self.locked_put(credentials)
  File "/base/data/home/apps/s~art-everywhere/7.385356767964097452/oauth2client/file.py", line 113, in locked_put
    f = open(self._filename, 'wb')
IOError: [Errno 30] Read-only file system: 'credentials.dat'
It looks like there's a problem with the write used in the library.

Here's a snippet of the code I used:

def login(cls):
    scope = 'https://picasaweb.google.com/data/'
    user_agent = 'picasawebuploader'
    # credential_store = os.path.join(os.path.split(__file__)[0], "credentials.dat")

    storage = Storage("credentials.dat")
    # storage = Storage(credential_store)
    credentials = storage.get()

    # user = users.get_current_user()
    # storage = StorageByKeyName(CredentialsModel, user.user_id(), 'credentials')
    # credentials = storage.get()

    if credentials is None or credentials.invalid:
        flow = flow_from_clientsecrets("client_secrets.json", scope=scope, redirect_uri='urn:ietf:wg:oauth:2.0:oob')
        uri = flow.step1_get_authorize_url()
        logging.info("uri: %s", uri)
        webbrowser.open(uri)
        code = "Here I posted the code retrived by the autentication"
        credentials = flow.step2_exchange(code)
        storage.put(credentials)

    if (credentials.token_expiry - datetime.utcnow()) < timedelta(minutes=5):
        http = httplib2.Http()
        http = credentials.authorize(http)
        credentials.refresh(http)

    gd_client = gdata.photos.service.PhotosService(source=user_agent,
                                                   email=USERNAME,
                                                   additional_headers={'Authorization' : 'Bearer %s' % credentials.access_token})

    return gd_client

What am I doing wrong? Thanks everyone for the help!

2

There are 2 answers

1
Jay Lee On

You can't create files in AppEngine like you would on a regular filesystem, it's read-only. You need to use special AppEngine credentials and storage objects.

1
stevenviola On

Ran into the same issue running the devserver on my local machine. The solution was not pretty, but this change solved it for me. I'm not sure if you'd be able run storage.put(credentials) from within appengine. This might be where a lot of the issue came from. Doing the oauth flow as part of a separate script, and then loading the credentials from the file actually worked for me after modifying the devserver.

I highly doubt that this would actually work in production though, so you might want to look into Delegating domain-wide authority to the service account