'How can I use Python Google API without getting a fresh auth code via browser each time?

I am playing with the Google API. I am using this as a starting point, here is the actual Python code.

I have created a OAuth 2.0 client ID at https://console.developers.google.com/apis/credentials and downloaded it as client_secret.json which is used in the code as follows:

CLIENT_SECRETS_FILE = "client_secret.json"

def get_authenticated_service():
  flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES)
  credentials = flow.run_console()
  return build(API_SERVICE_NAME, API_VERSION, credentials = credentials)

The contents of client_secret.json looks like this:

{
  "installed": {
    "client_id": "**REDACTED**",
    "project_id": "api-project-1014650230452",
    "auth_uri": "https:\/\/accounts.google.com\/o\/oauth2\/auth",
    "token_uri": "https:\/\/accounts.google.com\/o\/oauth2\/token",
    "auth_provider_x509_cert_url": "https:\/\/www.googleapis.com\/oauth2\/v1\/certs",
    "client_secret": "**REDACTED**",
    "redirect_uris": [
      "urn:ietf:wg:oauth:2.0:oob",
      "http:\/\/localhost"
    ]
  }
}

The whole program works and successfully returns a meaningful data set, however, each time I run the program I am prompted as follows:

Please visit this URL to authorize this application: https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=...
Enter the authorization code:

I enter the code and the program works, but I have to visit this URL and get a fresh code each time the program runs. I was under the impression that client_secret.json existed precisely to prevent this from being necessary.

What do I have to do to make my CLI Python program use the API without having to get a fresh token each time?



Solution 1:[1]

You want to run the script without retrieving the code every time. If my understanding is correct, how about this modification? In this modification, when the script is run for the first time, the refresh token is saved to a file of "credential_sample.json". By this, from the next run, you can use the API using the access token retrieved by the refresh token. So you are not required to retrieve the code every time.

Modified script :

Please modify as follows.

From :
def get_authenticated_service():
    flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES)
    credentials = flow.run_console()
    return build(API_SERVICE_NAME, API_VERSION, credentials = credentials)
To :
from oauth2client import client # Added
from oauth2client import tools # Added
from oauth2client.file import Storage # Added

def get_authenticated_service(): # Modified
    credential_path = os.path.join('./', 'credential_sample.json')
    store = Storage(credential_path)
    credentials = store.get()
    if not credentials or credentials.invalid:
        flow = client.flow_from_clientsecrets(CLIENT_SECRETS_FILE, SCOPES)
        credentials = tools.run_flow(flow, store)
    return build(API_SERVICE_NAME, API_VERSION, credentials=credentials)

Note :

  • When you run this for the first time, the browser is automatically opened. When you authorize the scopes, the script automatically retrieves the code and create the tokens to "credential_sample.json".
  • This modification supposes that your current script works except for being required to retrieve the code every time.

References :

If this was not what you want, I'm sorry.

Solution 2:[2]

After playing with a bunch of solutions, including the accepted answer, here's mine:

def get_authenticated_service():
    try:
        credentials = google.oauth2.credentials.Credentials.from_authorized_user_file(CLIENT_SECRETS_FILE)
    except ValueError as e: # first run with new secret.json (no refresh_token yet)
        flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES)
        credentials = flow.run_console()
        with open(CLIENT_SECRETS_FILE, 'w') as file:
            file.write(credentials.to_json())
    return build(API_SERVICE_NAME, API_VERSION, credentials=credentials)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tanaike
Solution 2