googleads / googleads-python-lib

The Python client library for Google's Ads APIs
Apache License 2.0
683 stars 975 forks source link

GoogleRefreshTokenClient could not authenticate to create AdManager Client - 401 Unauthorized #536

Closed khoinguyen19k8 closed 7 months ago

khoinguyen19k8 commented 11 months ago

I store my client_id, client_secret, and refresh_token in Google Secrets then retrieve them to initialize an AdManager Client. When I tried to get saved queries the server returned a 401 Unauthorized error.

oauth2_client = oauth2.GoogleRefreshTokenClient(
    client_id, client_secret, refresh_token)

# Initialize the Ad Manager client.
ad_manager_client = ad_manager.AdManagerClient(
    oauth2_client, application_name)
report_service = ad_manager_client.GetService("ReportService", version="v202305")

# Fetch the report query to request the report
statement = (ad_manager.StatementBuilder(version=config["ad_manager_version"])
                 .Where("id = :id")
                 .WithBindVariable("id", int(config["report_id"]))
                 .Limit(1))
response = report_service.getSavedQueriesByStatement(statement.ToStatement())
response.content =b'<HTML>\n<HEAD>\n<TITLE>Unauthorized</TITLE>\n</HEAD>\n<BODY BGCOLOR="#FFFFFF" TEXT="#000000">\n<H1>Unauthorized</H1>\n<H2>Error 401</H2>\n</BODY>\n</HTML>\n'

It worked when I used the service account route, that is to download the service account file to local storage then create oauth2_client using GoogleServiceAccountClient. However, due to some security reason I don't want to do this and using access token only. This approach should work as it had been documented here: https://github.com/googleads/googleads-python-lib/wiki/API-access-on-behalf-of-your-clients-(web-flow)#step-2---setting-up-the-client-library.

christopherseeley commented 7 months ago

Can you verify the scope you're using when generating the refresh token? It needs to be https://www.googleapis.com/auth/dfp.

Also, if your goal is to avoid having a file you can use a GoogleCredentialsClient and pass in any Credentials created from the google.auth package, like application default or a service account loaded from a dict: https://googleapis.dev/python/google-auth/latest/reference/google.auth.html#google.auth.load_credentials_from_dict