Search code examples
pythongoogle-apigoogle-drive-apigoogle-oauthgoogle-api-python-client

How to get access tokens using refresh token automatically on oauth 2.0


As you all can see, I'm new here. So point me out if there's any problem.

I'm having problems dealing with oauth2.0, specifically to get the access token.

I'm using this code right now:

#esse bloco serve para criar o access_token, e vai atualizar o access_token sempre, retornando ele para o principal
    SCOPES = 'https://www.googleapis.com/auth/drive'
    creds = None
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
    # Esse bloco pode ser um problema para um server. É sempre preciso rodar esse bloco em um desktop para obter as chaves com autenticação.
    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)
    # Salva as credenciais para uma proxima vez
    with open('token.json', 'w') as token:
        token.write(creds.to_json())
    a_file = open('token.json', "r")
    tokens = json.load(a_file)
    access_token = tokens['token']

This code has some problems:

  • On the first time it runs, it requires manual confirmation (a internet tab opens and then you have to click some stuff).
  • When the first access token expires, it doesn't work anymore (so the token is not refreshed).

Is there a way to do it automatically (without the need for a human) ? And how do I update access token using this ?

EDIT:

Since it was pointed out, here's the usual outcome of the token.json

{"token": "*******", "refresh_token": "*****", "token_uri": "********", "client_id": "*********************", "client_secret": "****************", "scopes": "https://www.googleapis.com/auth/drive", "expiry": "2021-09-17T15:45:39Z"}

Solution

  • Part one

    When the first access token expires, it doesn't work anymore (so the token is not refreshed).

    First thing Please check token.json and verify that there is a refresh token being stored. Or you can have a look at the code below.

    def initialize_drive():
      """Initializes the drive service object.
    
      Returns:
        drive an authorized drive service object.
      """
      # Parse command-line arguments.
      parser = argparse.ArgumentParser(
          formatter_class=argparse.RawDescriptionHelpFormatter,
          parents=[tools.argparser])
      flags = parser.parse_args([])
    
      # Set up a Flow object to be used if we need to authenticate.
      flow = client.flow_from_clientsecrets(
          CLIENT_SECRETS_PATH, scope=SCOPES,
          message=tools.message_if_missing(CLIENT_SECRETS_PATH))
    
      # Prepare credentials, and authorize HTTP object with them.
      # 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 = file.Storage('drive.dat')
      credentials = storage.get()
      if credentials is None or credentials.invalid:
        credentials = tools.run_flow(flow, storage, flags)
      http = credentials.authorize(http=httplib2.Http())
    
      # Build the service object.
      drive = build('drive', 'v3', http=http)
    
      return drive
    

    Part two

    Is there a way to do it automatically (without the need for a human) ? And how do I update access token using this ?

    Yes you can use a service account. Service accounts are like dummy users. A service account has its own google drive account so you can upload and download from that. You can also share a directory on your personal drive account with the service account like you would any other user. Then the service account would have permissions to upload and download from that. As it is pre authorized there will be no need for a user to consent to its access.

    Note: service accounts should only be used on a drive account that you the developer own. If you are accessing your users drive accounts then you should go with Oauth2.

    def initialize_drive():
      """Initializes an drive API V3 service object.
    
      Returns:
        An authorized Google Drive API V3 service object.
      """
      credentials = ServiceAccountCredentials.from_json_keyfile_name(
          KEY_FILE_LOCATION, SCOPES)
    
      # Build the service object.
      drive = build('drive', 'v3', credentials=credentials)
    
      return analytics
    

    Links