Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AccessTokenRefreshError: invalid_grant from oauth2client

I am creating a script that will download files for a particular Google Apps user using Google-api-python-client At first I'm trying to get the list of files that a users account contain. I'm following the example given in the link https://developers.google.com/drive/v2/reference/files/list

code block are given below

authorization of the client by the user

def authorize_application(request):

    #setting flow to get permission and code 
    flow = OAuth2WebServerFlow(CLIENT_ID, CLIENT_SECRET, OAUTH_SCOPE, REDIRECT_URI, ACCESS_TYPE)
    authorize_url = flow.step1_get_authorize_url()

    code = request.GET.get('code', '')

    if code:
        #import ipdb
        #ipdb.set_trace()
    #setting flow step2 to exchage code for access token    
        credential = flow.step2_exchange(code)

    #initialising httplib2 instance and building a DriveAPI service
        http = httplib2.Http()
        http = credential.authorize(http)
        drive_service = build('drive', 'v2', http=http)

        # getting user's data
    about = drive_service.about().get().execute()
        user_info = about.get('user')
        email = user_info.get('emailAddress')
        request.session['username'] = email[0:email.index('@')]
        username = request.session['username']
        #import ipdb
        #ipdb.set_trace()
        #creating a Django user object 
    user, created = User.objects.get_or_create(username=username, email=email)

    #saving credentials to database 
        if created == True: 
            storage = Storage(CredentialsModel, 'id', user, 'credential')
            storage.put(credential)
            return HttpResponseRedirect('/download/')
        else:
        return HttpResponseRedirect('/download/')
    else:
        return HttpResponseRedirect(authorize_url)

getting list of files in users Drive

def download_file(request):

    #import ipdb
    #ipdb.set_trace()

    username = request.session['username']
    user = User.objects.get(username=username)

    storage = Storage(CredentialsModel, 'id', user, 'credential')
    credential = storage.get()

    access_token = credential.access_token

    http = httplib2.Http()
    http = credential.authorize(http)
    drive_service = build('drive', 'v2', http=http)

    result = []
    page_token = access_token

    while True:

    try:
        param = {}
            if page_token:
                param['pageToken'] = page_token
            files = drive_service.files().list(**param).execute()

            result.extend(files['items'])
                page_token = files.get('nextPageToken')

        if not page_token:
        break
    except errors.HttpError, error:
        print 'An error occured: %s' % error
        break

    return HttpResponse(result)

It's saving and retrieving the credential from database but its giving error "AccessTokenRefreshError: invalid_grant" at files = drive_service.files().list(**param).execute() of download_file()

What I'm doing wrong? please suggest the right way.

like image 463
Vishnu Kant Avatar asked Nov 11 '22 04:11

Vishnu Kant


1 Answers

(Feb 2017) Not sure what your problem is/was, but a couple of things: 1) the Drive API has a newer version (v3), and 2) the auth code you used can now be simplified significantly with the recent updates in the Google APIs Client Library. (Make sure you update your Python libraries with pip install -U google-api-python-client [or pip3 for Python 3].)

Below's a working solution -- tell me if it works for you -- that I wrote up in this blog post and in this video. I left out the about() call to get the user info, but I divide the code up into the same 2 sections you had above, but as you can see, with much less code:

authorization of the client by the user

SCOPES = 'https://www.googleapis.com/auth/drive.readonly.metadata'
store = file.Storage('storage.json')
creds = store.get()
if not creds or creds.invalid:
    flow = client.flow_from_clientsecrets('client_id.json', SCOPES)
    creds = tools.run_flow(flow, store)

getting list of files in users Drive (the 1st 100 files)

DRIVE = discovery.build('drive', 'v3', http=creds.authorize(Http()))
files = DRIVE.files().list().execute().get('files', [])
for f in files:
    print(f['name'], f['mimeType'])

If you want to learn more about using the Drive API, here are some additional resources (videos, blog posts, etc.) I've created:

  • Google Drive: Uploading & Downloading Files video plus "Poor man's plain text to PDF converter" code deep dive post (*)
  • Exporting a Google Sheet as CSV blog post only

(*) - TL;DR: upload plain text file to Drive, import/convert to Google Docs format, then export that Doc as PDF. Post above uses Drive API v2 like your code sample; this follow-up post describes migrating it to Drive API v3, and here's a developer video combining both "poor man's converter" posts.

like image 78
wescpy Avatar answered Nov 15 '22 07:11

wescpy