I recently ran into this problem myself, trying to access the AdSense API. It doesn't help that Google's documentation is very sparse, uses Flask for some odd reason, implies you must retrieve an authorization_response
and not the actual authorization code
, and refers to a few different non-working Python examples, seemingly written for long-since deprecated Python 1.4.
However, based on their examples, and a few blog posts implementing some more recent fixes (but still broken when I tried them), I managed to piece together some working code.
My file utils.py
where I define the initialize_service
to initialize my connection to the AdSense API:
"""
Auxiliary file for AdSense Management API code samples.
Handles various tasks to do with logging, authentication and initialization.
"""
import os
from apiclient.discovery import build
from oauth2client.client import OAuth2Credentials
from oauth2client.file import Storage
from googleapiclient.http import build_http
import google_auth_oauthlib.flow
MY_DOMAIN = '<your domain here>'
def initialize_service():
"""Builds instance of service from discovery data and does auth."""
client_secrets = os.path.join(os.path.dirname(__file__), 'client_secrets.json')
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
client_secrets, scopes=['https://www.googleapis.com/auth/adsense.readonly'])
flow.redirect_uri = f'https://{MY_DOMAIN}/oauth2callback'
# If the credentials don't exist or are invalid run through the native client
# flow. The Storage object will ensure that if successful the good
# Credentials will get written back to a file.
storage = Storage('adsense.dat')
credentials = storage.get()
if credentials is None or credentials.invalid:
auth_url, _ = flow.authorization_url(prompt='consent')
print('Log into the Google Account you use to access your AdWords account ' \
'and go to the following URL: \n%s\n' % auth_url)
print('After approving the token enter the verification code (if specified).')
code = input('Code:').strip()
flow.fetch_token(code=code)
print('Access token: %s' % flow.credentials.token)
print('Refresh token: %s' % flow.credentials.refresh_token)
# Flow creates a google.oauth2.credentials.Credentials instance but storage
# can only save and load a oauth2client.client.Credentials
# instance, so we have to convert it.
old_creds = flow.credentials
good_creds = OAuth2Credentials(
access_token=old_creds.token,
client_id=old_creds.client_id,
client_secret=old_creds.client_secret,
refresh_token=old_creds.refresh_token,
token_expiry=old_creds.expiry,
token_uri=old_creds.token_uri,
user_agent='my-agent',
id_token=old_creds.id_token,
scopes=old_creds.scopes,
)
storage.put(good_creds)
credentials = storage.get()
http = credentials.authorize(http=build_http())
service = build("adsense", "v1.4", http=http)
return service
This is the code that should answer your question, because I get the authorization code, and call flow.fetch_token(code=code)
to convert this to a token, which I then store for future re-use in the file adsense.dat
.
The problem I ran into was that there are multiple classes from multiple packages for storing OAuth credentials, and they're all confusingly named the same thing, yet they're slightly incompatible. The flow.fetch_token()
function stores its credentials internally as a google.oauth2.credentials.Credentials
instance, yet the code for storing and loading these credentials only accepts an oauth2client.client.Credentials
instance, so I had to write some code to convert from one to the other.
Then, to call the API, you'd have code like:
from utils import initialize_service
service = initialize_service()
result = service.reports().generate(
startDate='<start date>',
endDate='<end date>',
filter=['AD_CLIENT_ID==<your ad client id>'],
metric=[
'PAGE_VIEWS',
'EARNINGS'
],
dimension=[
'AD_UNIT_NAME',
],
).execute()