pterodactella
pterodactella

Reputation: 121

Creating Google Credentials object for Google Drive API without loading from file

I am trying to create a google credentials object to access google drive. I have the tokens and user data stored in a session thus I am trying to create the object without loading them from a credentials.json file. I am handling the authentication when a user first logs in the web app and storing the tokens inside the user session, the session has a time out of 24 hours same as the default access token thus after 24 hours the user is requested to log in again so a new session with a valid access token is created. So my idea is to reuse the access token to limit the amount of log ins and improve user experience.

This is a small piece of code on how I'm trying to create the google credentials object

from oauth2client.client import GoogleCredentials

access_token = request.session['access_token']
gCreds = GoogleCredentials( 
         access_token, 
         os.getenv('GOOGLE_CLIENT_ID'),
         os.getenv('GOOGLE_CLIENT_SECRET'), 
         refresh_token=None, 
         token_expiry=None,
         token_uri=GOOGLE_TOKEN_URI, 
         user_agent='Python client library',
         revoke_uri=None)
build('drive', 'v3', credentials = gCred)


Whenever I try to run this code I get the following error:


Insufficient Permission: Request had insufficient authentication scopes.". Details: "[{'domain': 'global', 'reason': 'insufficientPermissions', 'message': 'Insufficient Permission: Request had insufficient authentication scopes.'}]"

{
 "error": {
  "errors": [
   {
    "domain": "usageLimits",
    "reason": "dailyLimitExceededUnreg",
    "message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
    "extendedHelp": "https://code.google.com/apis/console"
   }
  ],
  "code": 403,
  "message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup."
 }
}

Upvotes: 5

Views: 2101

Answers (2)

pterodactella
pterodactella

Reputation: 121

The object was build correctly, there was no issue with building the object this way

access_token = request.session['access_token']
gCreds = GoogleCredentials( 
         access_token, 
         os.getenv('GOOGLE_CLIENT_ID'),
         os.getenv('GOOGLE_CLIENT_SECRET'), 
         refresh_token=None, 
         token_expiry=None,
         token_uri=GOOGLE_TOKEN_URI, 
         user_agent='Python client library',
         revoke_uri=None)
build('drive', 'v3', credentials = gCred)

The problem was caused at an earlier stage, when registering the scopes

oauth = OAuth(config)
oauth.register(
    name='google',
    server_metadata_url='',
    client_kwargs={
        'scope': 'openid email profile https://www.googleapis.com/auth/drive.readonly'
    }
)

Upvotes: 1

Linda Lawton - DaImTo
Linda Lawton - DaImTo

Reputation: 117146

So what are scopes. Scopes define the access that you are requesting from the user. In this case you want to access their Google drive account, but how much access do you need depends upon the methods you will be using.

If you are just using file.list then you could request a read only scope as your not going to be writing anything.

https://www.googleapis.com/auth/drive.readonly

Yet if your going to use file.create well your going to need a write scope. You need permission to write to their google account

https://www.googleapis.com/auth/drive

I cant see from your code how you are handling the authorization at all. So Lets start by looking at the official google drive python sample

In the code below notice how they call

InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)

And define the scopes of access they would like to request.

from __future__ import print_function

import os.path

from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError

# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly']


def main():
    """Shows basic usage of the Drive v3 API.
    Prints the names and ids of the first 10 files the user has access to.
    """
    creds = None
    # The file token.json stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.json', 'w') as token:
            token.write(creds.to_json())

    try:
        service = build('drive', 'v3', credentials=creds)

        # Call the Drive v3 API
        results = service.files().list(
            pageSize=10, fields="nextPageToken, files(id, name)").execute()
        items = results.get('files', [])

        if not items:
            print('No files found.')
            return
        print('Files:')
        for item in items:
            print(u'{0} ({1})'.format(item['name'], item['id']))
    except HttpError as error:
        # TODO(developer) - Handle errors from drive API.
        print(f'An error occurred: {error}')


if __name__ == '__main__':
    main()

the error message

The error message

Request had insufficient authentication scopes.". Details: "[{'domain': 'global', 'reason': 'insufficientPermissions', 'message': 'Insufficient Permission: Request had insufficient authentication scopes.'}]"> successfully connected to drive

Actually means that you have requsted one scope from the user lets say read only yet you are trying to use it with a method that requires write access. So your request has insufficient authentication scopes.

Fix your code to request the proper scope delete the refresh token you have now and request authorization of the user again with the proper scope.

Upvotes: 3

Related Questions