Automating pydrive verification process

alvas picture alvas · Jun 25, 2014 · Viewed 28.4k times · Source

I am trying to automate the GoogleAuth process when using the pydrive library (https://pypi.python.org/pypi/PyDrive).

I've set up the pydrive and the google API such that my secret_client.json works but it requires web authentication for gdrive access every time i run my script:

from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive

gauth = GoogleAuth()
gauth.LocalWebserverAuth()

drive = GoogleDrive(gauth)

textfile = drive.CreateFile()
textfile.SetContentFile('eng.txt')
textfile.Upload()
print textfile

drive.CreateFile({'id':textfile['id']}).GetContentFile('eng-dl.txt')

eng.txt is just a textfile. Moreover when I try to use the above script while I am logged into another account. It doesn't upload the eng.txt into my gdrive that generated the secret_client.json but the account that was logged in when I authorize the authentication

From the previous post, I've tried the following to automate the verification process but it's giving error messages:

import base64, httplib2
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive

from apiclient.discovery import build
from oauth2client.client import SignedJwtAssertionCredentials
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive

#gauth = GoogleAuth()
#gauth.LocalWebserverAuth()

# from google API console - convert private key to base64 or load from file
id = "464269119984-j3oh4aj7pd80mjae2sghnua3thaigugu.apps.googleusercontent.com"
key = base64.b64decode('COaV9QUlO1OdqtjMiUS6xEI8')

credentials = SignedJwtAssertionCredentials(id, key, scope='https://www.googleapis.com/auth/drive')
credentials.authorize(httplib2.Http())

gauth = GoogleAuth()
gauth.credentials = credentials

drive = GoogleDrive(gauth)

drive = GoogleDrive(gauth)

textfile = drive.CreateFile()
textfile.SetContentFile('eng.txt')
textfile.Upload()
print textfile

drive.CreateFile({'id':textfile['id']}).GetContentFile('eng-dl.txt')

Error:

Traceback (most recent call last):
  File "/home/alvas/git/SeedLing/cloudwiki.py", line 29, in <module>
    textfile.Upload()
  File "/usr/local/lib/python2.7/dist-packages/pydrive/files.py", line 216, in Upload
    self._FilesInsert(param=param)
  File "/usr/local/lib/python2.7/dist-packages/pydrive/auth.py", line 53, in _decorated
    self.auth.Authorize()
  File "/usr/local/lib/python2.7/dist-packages/pydrive/auth.py", line 422, in Authorize
    self.service = build('drive', 'v2', http=self.http)
  File "/usr/local/lib/python2.7/dist-packages/oauth2client/util.py", line 132, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/apiclient/discovery.py", line 192, in build
    resp, content = http.request(requested_url)
  File "/usr/local/lib/python2.7/dist-packages/oauth2client/util.py", line 132, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/oauth2client/client.py", line 475, in new_request
    self._refresh(request_orig)
  File "/usr/local/lib/python2.7/dist-packages/oauth2client/client.py", line 653, in _refresh
    self._do_refresh_request(http_request)
  File "/usr/local/lib/python2.7/dist-packages/oauth2client/client.py", line 677, in _do_refresh_request
    body = self._generate_refresh_request_body()
  File "/usr/local/lib/python2.7/dist-packages/oauth2client/client.py", line 861, in _generate_refresh_request_body
    assertion = self._generate_assertion()
  File "/usr/local/lib/python2.7/dist-packages/oauth2client/client.py", line 977, in _generate_assertion
    private_key, self.private_key_password), payload)
  File "/usr/local/lib/python2.7/dist-packages/oauth2client/crypt.py", line 131, in from_string
    pkey = crypto.load_pkcs12(key, password).get_privatekey()
OpenSSL.crypto.Error: [('asn1 encoding routines', 'ASN1_get_object', 'header too long')]

My authentication on gdrive api looks like this:

enter image description here

How could I use pydrive such that I do not need to authenticate everytime I use it?

How to allow automatic authentication such that the python script using the pydrive script will only upload to the account that generated the secret_client.json and not the currently logged on account on the internet browser?

Answer

dano picture dano · Jul 3, 2014

First, you're misunderstanding one very important bit of how this works:

when I try to use the above script while I am logged into another account. It doesn't upload the eng.txt into my gdrive that generated the secret_client.json but the account that was logged in when I authorize the authentication

This is exactly how it's supposed to work. You, as the developer, distribute client_secret.json with your application, and that file is used by PyDrive to authenticate the application with Google. Google wants to know how many API requests are being made by each application out there for all sorts of reasons (metrics, charge the account, revoke access, etc.), so it requires the application to authenticate itself.

Now, when your application runs LocalWebserverAuth, it's authenticating the client with Google. The client, of course, is the person actually using your application. In this case, the developer and client are the same person (you), but imagine your want to distribute your application to a million different people. They need to be able to authenticate themselves and upload files to their own Drive account, rather that having them all end up in yours (the developer), who provided client_secret.json.

That said, it's really just a very minor change to make it so your app doesn't have to ask the client to authenticate every time you run the app. You just need to use LoadCredentialsFile and SaveCredentialsFile.

from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive

gauth = GoogleAuth()
# Try to load saved client credentials
gauth.LoadCredentialsFile("mycreds.txt")
if gauth.credentials is None:
    # Authenticate if they're not there
    gauth.LocalWebserverAuth()
elif gauth.access_token_expired:
    # Refresh them if expired
    gauth.Refresh()
else:
    # Initialize the saved creds
    gauth.Authorize()
# Save the current credentials to a file
gauth.SaveCredentialsFile("mycreds.txt")

drive = GoogleDrive(gauth)

textfile = drive.CreateFile()
textfile.SetContentFile('eng.txt')
textfile.Upload()
print textfile

drive.CreateFile({'id':textfile['id']}).GetContentFile('eng-dl.txt')