googleapis / google-auth-library-python

Google Auth Python Library
https://googleapis.dev/python/google-auth/latest/
Apache License 2.0
778 stars 308 forks source link

'Credentials' object has no attribute 'authorize' #190

Closed cosbgn closed 7 years ago

cosbgn commented 7 years ago

I'm migrating my app from the depriciated oAuth2Client to this library. I use requests_oauthlib to get the refresh_token, the access_token and all the rest. Then I build the credential object like this:

    credentials = google.oauth2.credentials.Credentials(
                                                        access_token,
                                                        refresh_token = refresh_token,
                                                        token_uri = 'https://accounts.google.com/o/oauth2/token',
                                                        client_id = settings.GOOGLE_CLIENT_ID,
                                                        client_secret = settings.GOOGLE_CLIENT_SECRET
                                                        )

I'm not sure about the token_uri, what am I supposed to put there? In any case this seems to work, making a simple call like this one:

    authed_session = AuthorizedSession(credentials)
    response = authed_session.get('https://www.googleapis.com/oauth2/v1/userinfo') 

works as expected and I do get back the results. However my app relies a lot on the Google Analytic api, which uses its own build method.

With oAuth2client I used to do (to get properties using v3):

    http = httplib2.Http()
    http = credentials.authorize(http)
    v3 = build('analytics', 'v3', http=http)
    try:
        account_summaries = v3.management().accountSummaries().list().execute()
    except Exception as error:
        return error_page(request, error)
    google_email = account_summaries['username']

And to get metrics with v4:

    http = credentials.authorize(httplib2.Http())
    DISCOVERY_URI = ('https://analyticsreporting.googleapis.com/$discovery/rest')
    analytics = build('analytics', 'v4', http=http, discoveryServiceUrl=DISCOVERY_URI)

and then: analytics.reports().batchGet( ...........etc)

However now that I migrate to this library I don't know how I can use the build method. All the documentation is really old and still referencing the depreciated library. How can I authenticate and use correctly google-auth with the Google Analytics API?

Thanks

theacodes commented 7 years ago

@Cosbgn when using google-auth with google-api-python-client you only need to specify the credentials to discovery - you do not need to construct your own http instance. So:

v3 = build('analytics', 'v3', credentials=credentials)
try:
    account_summaries = v3.management().accountSummaries().list().execute()
except Exception as error:
    return error_page(request, error)
google_email = account_summaries['username']

Should work.

adamwilbert commented 7 years ago

@jonparrott I am encountering a similar error, when I attempt to use the build method, even when passing my credentials rather than http as recommended in your code block I still get

'Credentials' object has no attribute 'authorize'

theacodes commented 7 years ago

What version of the client library are you using?

On Tue, Aug 15, 2017, 4:33 PM Adam Wilbert notifications@github.com wrote:

@jonparrott https://github.com/jonparrott I am encountering a similar error, when I attempt to use the build method, even when passing my credentials rather than http as recommended in your code block I still get

'Credentials' object has no attribute 'authorize'

— You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub https://github.com/GoogleCloudPlatform/google-auth-library-python/issues/190#issuecomment-322617580, or mute the thread https://github.com/notifications/unsubscribe-auth/AAPUc8LmRknS1JzF_OoudC_1h5oq1mLTks5sYirWgaJpZM4O1ROP .

cosbgn commented 7 years ago

@adamwilbert You are much better off using requests and just the rest endpoints, here is an example of a call with v3 and v4. I hope i helps: with v3:

    access_token = get_access_token(user)
    url = 'https://www.googleapis.com/analytics/v3/management/accountSummaries?access_token={0}'.format(access_token)
    r = requests.get(url)
    ga_data = r.json()

With v4:

view_id = callback_args
    access_token = get_access_token(user)
    url = 'https://analyticsreporting.googleapis.com/v4/reports:batchGet'
    headers = {"Authorization":"Bearer {0}".format(access_token)}
    data =  {
             "reportRequests": [
              {
               "viewId": view_id,
               "dateRanges": [{ "startDate": "30daysAgo", "endDate": "today" }],
               "metrics": [{"expression": "ga:sessions"},],
               "dimensions": [{"name": "ga:pagePath"}],
               "orderBys": [{"fieldName": 'ga:sessions', "sortOrder": 'DESCENDING'}],
            }]}
    r = requests.post(url, json=data, headers=headers)
    ga_data = r.json()

You will also need a function which checks the validity of the token and if invalid requests a new one, I use:

access_token = creds.access_token
    url = 'https://www.googleapis.com/oauth2/v3/tokeninfo?access_token={0}'.format(access_token)
    r = requests.get(url)
    data = r.json()
    try:
        expires_in = data['expires_in']
        print('Token Valid')
        return access_token
    except KeyError:
        print('Token not valid anymore, asking for a new one..')
        data = {
                'refresh_token':refresh_token,
                'client_id':.GOOGLE_CLIENT_ID,
                'client_secret':GOOGLE_CLIENT_SECRET,
                'grant_type':'refresh_token'}
        url = 'https://www.googleapis.com/oauth2/v4/token'
        r = requests.post(url, data=data)
        new_token = r.json()
        token_saver(new_token, user)
        return new_token['access_token']

I hope it helps!

adamwilbert commented 7 years ago

I have actually also tried using a service_account credential, same error

google-api-python-client==1.4.1

@jonparrott is there a known compatibility issue?

theacodes commented 7 years ago

@adamwilbert support for google-auth was added in release 1.6.0 so you'll need to update to use it.

@Cosbgn your response, while well intentioned, is a bit misleading. Using requests directly is fine and personal preference, but this library can actually help there. It handles adding the authorization header and handling refresh - see google.auth.transport.requests.AuthorizedSession.

adamwilbert commented 7 years ago

@jonparrott even with google-api-python-client==1.6.2 and google-auth==1.0.2

I am still getting the 'Credentials' object has no attribute 'authorize' error

theacodes commented 7 years ago

@adamwilbert can you show me your code and the full stacktrace?

adamwilbert commented 7 years ago
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/oauth2client/util.py", line 140, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/googleapiclient/discovery.py", line 231, in build
    credentials=credentials)
  File "/usr/local/lib/python3.5/dist-packages/oauth2client/util.py", line 140, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/googleapiclient/discovery.py", line 370, in build_from_document
    http = _auth.authorized_http(credentials)
  File "/usr/local/lib/python3.5/dist-packages/googleapiclient/_auth.py", line 92, in authorized_http
    return credentials.authorize(build_http())
AttributeError: 'Credentials' object has no attribute 'authorize'

Failed API: LotViews 'Credentials' object has no attribute 'authorize'
    from google.oauth2 import service_account
    from apiclient import discovery

    credentials = service_account.Credentials.from_service_account_file(
        private_key_file)

    discovery.build(
        GOOGLE_ANALYTICS_SERVICE_NAME,
        GOOGLE_ANALYTICS_SERVICE_VERSION,
        credentials=credentials
    )
theacodes commented 7 years ago

@adamwilbert thanks, I just tried and I can't reproduce - just to be extra extra sure can you do:

import googleapiclient
print(googleapiclient.__version__)
adamwilbert commented 7 years ago

1.6.2

theacodes commented 7 years ago

Ah - I think I know what's up- can you also install google-auth-httplib2?

adamwilbert commented 7 years ago

Getting a 403 now, which is a start :)

Thanks!

For future reference is google-auth-httplib2 a parallel dependency for what I'm attempting?

theacodes commented 7 years ago

Hey hey, progress! :)

Let me know if I can do anything to help from here. I think I'm going to add a better error message to googleapiclient to say that it needs google-auth-httplib2 if you pass it google-auth credentials.

adamwilbert commented 7 years ago

Awesome! That would be super helpful!

tushuhei commented 7 years ago

I encountered a similar issue and solved the problem by installing google-auth-httplib2. It should be very helpful to add an error message for that instruction.

damienrj commented 7 years ago

This error just started happening to me, though it was working until recently without google-auth-httplib2 being installed (or it stopped being installed by pip automatically). I also had to install directly via the wheel since the pip install didn't see it for some reason. Installing google-auth-httplib2 did fix the problem. The error message I got helped though.

That aside, what is the best way to pass in the credentials?

googleapiclient/_auth.py", line 97, in authorized_http
    'Credentials from google.auth specified, but '
ValueError: Credentials from google.auth specified, but google-api-python-client is unable to use these credentials unless google-auth-httplib2 is installed. Please install google-auth-httplib2.
theacodes commented 7 years ago

what is the best way to pass in the credentials?

googleapiclient.discovery.build('api', 'version', credentials=credentials)
brandon-white commented 7 years ago
google-api-python-client==1.6.4
google-auth==1.1.1
google-auth-httplib2==0.0.2
google-cloud-core==0.27.1
google-cloud-storage==1.5.0
google-resumable-media==0.3.0
googleapis-common-protos==1.5.3

Using the latest pip installs. But still getting

  File "/home/bwhite/research/experiment_framework/experiment_io/load_training_experiment.py", line 72, in load_results
    blob_paths = list_blobs(self.results_bucket, self.results_path)
  File "/home/bwhite/research/utilities/gcloud/gcloud_storage.py", line 115, in list_blobs
    bucket = client.get_bucket(bucket_name)
  File "/home/bwhite/research/env/lib/python3.5/site-packages/gcloud/storage/client.py", line 167, in get_bucket
    bucket.reload(client=self)
  File "/home/bwhite/research/env/lib/python3.5/site-packages/gcloud/storage/_helpers.py", line 77, in reload
    _target_object=self)
  File "/home/bwhite/research/env/lib/python3.5/site-packages/gcloud/connection.py", line 343, in api_request
    target_object=_target_object)
  File "/home/bwhite/research/env/lib/python3.5/site-packages/gcloud/connection.py", line 241, in _make_request
    return self._do_request(method, url, headers, data, target_object)
  File "/home/bwhite/research/env/lib/python3.5/site-packages/gcloud/connection.py", line 269, in _do_request
    return self.http.request(uri=url, method=method, headers=headers,
  File "/home/bwhite/research/env/lib/python3.5/site-packages/gcloud/connection.py", line 100, in http
    self._http = self._credentials.authorize(self._http)
AttributeError: 'Credentials' object has no attribute 'authorize'
theacodes commented 7 years ago

@brandon-white it's weird to see gcloud in the path there - the gcloud distribution was discontinued some time ago.

artly commented 6 years ago

Same error here, the traceback as follows:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-140-5d89754385bf> in <module>()
      1 ytservice = build(YOUTUBE_API_SERVICE_NAME, 
      2             YOUTUBE_API_VERSION,
----> 3             credentials=credentials)
      4 

~/anaconda3/lib/python3.6/site-packages/googleapiclient/_helpers.py in positional_wrapper(*args, **kwargs)
    128                 elif positional_parameters_enforcement == POSITIONAL_WARNING:
    129                     logger.warning(message)
--> 130             return wrapped(*args, **kwargs)
    131         return positional_wrapper
    132 

~/anaconda3/lib/python3.6/site-packages/googleapiclient/discovery.py in build(serviceName, version, http, discoveryServiceUrl, developerKey, model, requestBuilder, credentials, cache_discovery, cache)
    223       return build_from_document(content, base=discovery_url, http=http,
    224           developerKey=developerKey, model=model, requestBuilder=requestBuilder,
--> 225           credentials=credentials)
    226     except HttpError as e:
    227       if e.resp.status == http_client.NOT_FOUND:

~/anaconda3/lib/python3.6/site-packages/googleapiclient/_helpers.py in positional_wrapper(*args, **kwargs)
    128                 elif positional_parameters_enforcement == POSITIONAL_WARNING:
    129                     logger.warning(message)
--> 130             return wrapped(*args, **kwargs)
    131         return positional_wrapper
    132 

~/anaconda3/lib/python3.6/site-packages/googleapiclient/discovery.py in build_from_document(service, base, future, http, developerKey, model, requestBuilder, credentials)
    362 
    363       # Create an authorized http instance
--> 364       http = _auth.authorized_http(credentials)
    365 
    366     # If the service doesn't require scopes then there is no need for

~/anaconda3/lib/python3.6/site-packages/googleapiclient/_auth.py in authorized_http(credentials)
    102                                                    http=build_http())
    103     else:
--> 104         return credentials.authorize(build_http())
    105 
    106 

AttributeError: 'Credentials' object has no attribute 'authorize'

The code that triggers it is:

from apiclient.discovery import build
from google.oauth2 import service_account
SCOPES = ['https://www.googleapis.com/auth/youtube']
SERVICE_ACCOUNT_FILE = 'ytmentions.json'
credentials = service_account.Credentials.from_service_account_file(
        SERVICE_ACCOUNT_FILE, scopes=SCOPES)
ytservice = build(YOUTUBE_API_SERVICE_NAME, 
            YOUTUBE_API_VERSION, 
            credentials=credentials)

googleapiclient version 1.6.7

Any possible help would be highly appreciated

theacodes commented 6 years ago

Hey @Cosbgn can you file a new bug if you're still experiencing this (and please include the output of pip freeze as well).

theacodes commented 6 years ago

Sorry, I meant @artly.

artly commented 6 years ago

@theacodes sure, sorry I didn't notice the issue is closed.

cmosguy commented 6 years ago

For anyone stumbling upon this, you need to make sure you do a pip install command:

pip install --upgrade google-api-python-client
pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2
pip install --upgrade requests

DO NOT USE conda to install it did not work properly from the conda-forge system.

Sridevi-10 commented 4 years ago
I am getting the same exception using Airflow version 1.10.3-composer. I have installed these python packages google-auth google-auth-oauthlib google-auth-httplib2 as suggested, but the issue is not resolved, please suggest on how to resolve this issue.

These are the all the versions I am using in this environment , google-api-core 1.16.0
google-api-python-client 1.7.8
google-apitools 0.5.28
google-auth 1.11.2
google-auth-httplib2 0.0.3
google-auth-oauthlib 0.4.0
google-cloud-bigquery 1.10.1
google-cloud-bigtable 0.32.0
google-cloud-container 0.2.1
google-cloud-core 0.29.1
google-cloud-language 1.2.0
google-cloud-logging 1.9.1
google-cloud-monitoring 0.31.1
google-cloud-spanner 1.8.0
google-cloud-storage 1.13.2

JDeepD commented 4 years ago

Hey hey, progress! :)

Let me know if I can do anything to help from here. I think I'm going to add a better error message to googleapiclient to say that it needs google-auth-httplib2 if you pass it google-auth credentials.

I installed google-auth-httplib2 .

When I import it , I get this error :

import google-auth-httplib2
             ^
SyntaxError: invalid syntax

Version :

google-api-python-client 1.12.3

google-api-core 1.22.3
google-api-python-client 1.12.3
google-auth 1.22.0
google-auth-httplib2 0.0.4
google-auth-oauthlib 0.4.1
googleapis-common-protos 1.52.0
httplib2 0.18.1

Serge-Mazur commented 3 years ago

Hi! I'm getting the same error:

Traceback (most recent call last):
  File "/home/Serge-M/.local/lib/python3.9/site-packages/telegram/ext/dispatcher.py", line 555, in process_update
    handler.handle_update(update, self, check, context)
  File "/home/Serge-M/.local/lib/python3.9/site-packages/telegram/ext/handler.py", line 198, in handle_update
    return self.callback(update, context)
  File "/home/Serge-M/bot-test/tggdrive.py", line 17, in gdrive_info
    driveV3 = build('drive', 'v3', credentials=SERVICE_ACCOUNT_CREDENTIALS)
  File "/home/Serge-M/.local/lib/python3.9/site-packages/googleapiclient/_helpers.py", line 131, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/home/Serge-M/.local/lib/python3.9/site-packages/googleapiclient/discovery.py", line 298, in build
    service = build_from_document(
  File "/home/Serge-M/.local/lib/python3.9/site-packages/googleapiclient/_helpers.py", line 131, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/home/Serge-M/.local/lib/python3.9/site-packages/googleapiclient/discovery.py", line 600, in build_from_document
    http = _auth.authorized_http(credentials)
  File "/home/Serge-M/.local/lib/python3.9/site-packages/googleapiclient/_auth.py", line 119, in authorized_http
    return credentials.authorize(build_http())
AttributeError: 'tuple' object has no attribute 'authorize'

I use these libraries: python-telegram-bot>=13.7 google-cloud-secret-manager>=2.7.2 google-api-python-client>=2.26.1 google-auth>=2.3.0 google-auth-oauthlib>=0.4.6 google-auth-httplib2>=0.1.0

My code is this one and it's being run on my Virtual Machine on my Google Cloud account:

from google import auth
from googleapiclient.discovery import build

SERVICE_ACCOUNT_CREDENTIALS = auth.default()

driveV3 = build('drive', 'v3', credentials=SERVICE_ACCOUNT_CREDENTIALS)
aboutUserDict = driveV3.about().get(fields='user').execute()

Please, help. 😐


Update (2021-10-25)

Turned out auth.default() returns a tuple. So the correct code is this one:

scopes = [
    'https://www.googleapis.com/auth/cloud-platform'
    'https://www.googleapis.com/auth/spreadsheets.readonly',
]
credentials, project_id = auth.default(scopes=scopes)

driveV3 = build('drive', 'v3', credentials=credentials)

And specifically for the Drive API the code doesn't work because Drive is not included in Google Cloud service accounts. :| So you have to download your JSON file with your service account credentials from Google Cloud Platform dashboard anyway.

xanjay commented 2 years ago

Hi @adamwilbert, Can you share which solution worked for you?

rnag commented 1 year ago

Hi all, I was running into a very similar issue:

'Credentials' object has no attribute 'authorize'

I successfully resolved it after referring the Quickstart Section in Python.

For more info, check out my answer here that I added on SO, for tips on how I resolved my issue and was able to get it working.