How to use refresh tokens in Google YouTube Data API?

Viewed 65

My code throws the following error:

google.auth.exceptions.RefreshError: ('invalid_grant: Bad Request', {'error': 'invalid_grant', 'error_description': 'Bad Request'}

I have this issue permanently and if I soluted it after a day is the same issue again here.

Is it possible to create a token that does not expire in 24 hours?

My current code is as follows.

import http.client
import httplib2
import os
import random
import time
import datetime
from Google import Create_Service
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from googleapiclient.http import MediaFileUpload
from google_auth_oauthlib.flow import InstalledAppFlow
import httplib2
httplib2.RETRIES = 1

MAX_RETRIES = 10

RETRIABLE_EXCEPTIONS = (httplib2.HttpLib2Error, IOError, http.client.NotConnected,
  http.client.IncompleteRead, http.client.ImproperConnectionState,
  http.client.CannotSendRequest, http.client.CannotSendHeader,
  http.client.ResponseNotReady, http.client.BadStatusLine)

RETRIABLE_STATUS_CODES = [500, 502, 503, 504]

CLIENT_SECRETS_FILE = 'test.json'


SCOPES = ['https://www.googleapis.com/auth/youtube.upload']
API_NAME = 'youtube'
API_VERSION = 'v3'

VALID_PRIVACY_STATUSES = ('public', 'private', 'unlisted')





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

def initialize_upload(youtube,body,file):

  
  insert_request = youtube.videos().insert(
    part='snippet,status',
    body=body,
    media_body=MediaFileUpload(file, chunksize=-1, resumable=True))
  response = resumable_upload(insert_request)
  return response
  
def resumable_upload(request):
  response = None
  error = None
  retry = 0
  while response is None:
    try:
      print('Uploading file...')
      status, response = request.next_chunk()
      if response is not None:
        if 'id' in response:
          print('Video id "%s" was successfully uploaded.' % response['id'])
        else:
          exit('The upload failed with an unexpected response: %s' % response)
    except HttpError as e:
      if e.resp.status in RETRIABLE_STATUS_CODES:
        error = 'A retriable HTTP error %d occurred:\n%s' % (e.resp.status,
                                                             e.content)
      else:
        raise
    except RETRIABLE_EXCEPTIONS as e:
      error = 'A retriable error occurred: %s' % e

    if error is not None:
      print(error)
      retry += 1
      if retry > MAX_RETRIES:
        exit('No longer attempting to retry.')

      max_sleep = 2 ** retry
      sleep_seconds = random.random() * max_sleep
      print('Sleeping %f seconds and then retrying...' % sleep_seconds)
      time.sleep(sleep_seconds)
  return response['id']



def main(request_body):

  youtube = Create_Service(CLIENT_SECRETS_FILE, API_NAME, API_VERSION, SCOPES)
  try:
    response = initialize_upload(youtube,request_body,"output.mp4" )
    print(response)
  except HttpError as e:
    print('An HTTP error %d occurred:\n%s' % (e.resp.status, e.content))

  youtube.thumbnails().set(
    videoId=response,
    media_body=MediaFileUpload('thumbnail.png')
  ).execute()
tags =["pencilmation","cartoons","animated cartoons characters","pencil animation","stick figure animations","animation characters","animated cartoon","animated short films","pencilmation","2d animation","pencil mation","funny animation","splendid cartoon","cartoon series","animated shorts","youtube cartoons","animation","pencilmate","funny cartoon","cartoons","pencilmiss","pencil","stick figure","ross bollinger","funny video"]
title1 = "Sunday Mood"
title2 = "Songs that put you in a good mood"
description = """Music is a powerful tool for relaxation and focus concentration.
When you're struggling with creative blocks or procrastination lag, it can help you relax your mind and tune be you better into prepared continuing to continue what you've been doing.
Even The the right music has can the also power to make boring activities more enjoyable fun. This channel is designed to bring you the most relaxing and peaceful music in the world. With Combining a mix of Downtempo,  Future garage , Chill step,Chill out and Ambient, we try strive to 
offer provide you with the best selection media of options media for your relaxation and entertainment.
If you liked like this video, give please like it a like , comment, or subscribe to the channel subscription .

If you are a filmmaker interested in promoting your content, contact us at:
lukaskap885@protonmail.com

⚠️ These videos may cause people with photosensitive epilepsy to convulse in seizures. Viewer discretion is advised. ⚠️
!!!
If any producer has an issue with any of the uploads contact us and us will delete it immediately. My email: lukaskap885@protonmail.com        
!!!

pencilmation cartoons,animated cartoons characters,pencil animation,stick figure animations,animation characters,animated cartoon,animated short films,pencilmation,2d animation,pencil mation,funny animation,splendid cartoon,cartoon series,animated shorts,youtube cartoons,animation,pencilmate,funny cartoon,cartoons,pencilmiss,pencil,stick figure,ross bollinger,funny video,

#AmazingMusicPlanet,#music,#music mix

Music is a powerful tool for relaxation and focus concentration.
When you're struggling with creative blocks or procrastination lag, it can help you relax your mind and tune be you better into prepared continuing to continue what you've been doing.
Even The the right music has can the also power to make boring activities more enjoyable fun. This channel is designed to bring you the most relaxing and peaceful music in the world. With Combining a mix of Downtempo,  Future garage , Chill step,Chill out and Ambient, we try strive to 
offer provide you with the best selection media of options media for your relaxation and entertainment.
If you liked like this video, give please like it a like , comment, or subscribe to the channel subscription .

If you are a filmmaker interested in promoting your content, contact us at:
lukaskap885@protonmail.com

⚠️ These videos may cause people with photosensitive epilepsy to convulse in seizures. Viewer discretion is advised. ⚠️
!!!
If any producer has an issue with any of the uploads contact us and us will delete it immediately. My email: lukaskap885@protonmail.com        
!!!

pencilmation cartoons,animated cartoons characters,pencil animation,stick figure animations,animation characters,animated cartoon,animated short films,pencilmation,2d animation,pencil mation,funny animation,splendid cartoon,cartoon series,animated shorts,youtube cartoons,animation,pencilmate,funny cartoon,cartoons,pencilmiss,pencil,stick figure,ross bollinger,funny video,

#AmazingMusicPlanet,#music,#music mix
"""
upload_video_time = "23. 8. 2022"
request_body = {
    'snippet': {
        'categoryI': 10,
        'title': f"{title1} | {title2} | AMP",
        'description': description,
        'tags': tags
    },
    'status': {
        'privacyStatus': 'private',
        'publishAt': upload_video_time ,
        'selfDeclaredMadeForKids': False, 
    },
    'notifySubscribers': False
}
main(request_body)

Googly.py:

import pickle
import os
from google_auth_oauthlib.flow import Flow, InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload, MediaIoBaseDownload
from google.auth.transport.requests import Request
import datetime


def Create_Service(client_secret_file, api_name, api_version, *scopes):
    print(client_secret_file, api_name, api_version, scopes, sep='-')
    CLIENT_SECRET_FILE = client_secret_file
    API_SERVICE_NAME = api_name
    API_VERSION = api_version
    SCOPES = [scope for scope in scopes[0]]
    print(SCOPES)

    cred = None

    pickle_file = f'token_{API_SERVICE_NAME}_{API_VERSION}.pickle'
    print(pickle_file)

    if os.path.exists(pickle_file):
        with open(pickle_file, 'rb') as token:
            cred = pickle.load(token)
            print(cred)

    if not cred or not cred.valid:
        if cred and cred.expired and cred.refresh_token:
            cred.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRET_FILE, SCOPES)
            cred = flow.run_console()

        with open(pickle_file, 'wb') as token:
            pickle.dump(cred, token)

    try:
        service = build(API_SERVICE_NAME, API_VERSION, credentials=cred)
        print(API_SERVICE_NAME, 'service created successfully')
        return service
    except Exception as e:
        print('Unable to connect.')
        print(e)
        return None

def convert_to_RFC_datetime(year=1900, month=1, day=1, hour=0, minute=0):
    dt = datetime.datetime(year, month, day, hour, minute, 0).isoformat() + 'Z'
    return dt

The stacktrace:

test.json-youtube-v3-(['https://www.googleapis.com/auth/youtube.upload'],)
['https://www.googleapis.com/auth/youtube.upload']
Traceback (most recent call last):
  File "c:/Users/Lukas/OneDrive - ZSMosBB/Dokumenty/python_scripts/AMP/video_uploads2.py", line 155, in <module>
    main(request_body)
  File "c:/Users/Lukas/OneDrive - ZSMosBB/Dokumenty/python_scripts/AMP/video_uploads2.py", line 90, in main
    youtube = Create_Service(CLIENT_SECRETS_FILE, API_NAME, API_VERSION, SCOPES)
  File "C:\Users\Lukas\AppData\Local\Programs\Python\Python38\lib\site-packages\Google.py", line 29, in Create_Service
    cred.refresh(Request())
  File "C:\Users\Lukas\AppData\Local\Programs\Python\Python38\lib\site-packages\google\oauth2\credentials.py", line 302, in refresh
    ) = reauth.refresh_grant(
  File "C:\Users\Lukas\AppData\Local\Programs\Python\Python38\lib\site-packages\google\oauth2\reauth.py", line 347, in refresh_grant
    _client._handle_error_response(response_data)
  File "C:\Users\Lukas\AppData\Local\Programs\Python\Python38\lib\site-packages\google\oauth2\_client.py", line 62, in _handle_error_response  
    raise exceptions.RefreshError(error_details, response_data)
google.auth.exceptions.RefreshError: ('invalid_grant: Bad Request', {'error': 'invalid_grant', 'error_description': 'Bad Request'})
2 Answers

Access tokens by design expire after an hour. refresh tokens expire after seven days if your app is in testing phase, if its in production then it will not expire.

These are things that are configured by the authorization server, this being google. It is not something you can change.

As for why your token is expiring after 24 hours the only thing i can think of is that you are authorizing the user more then 50 times in 24 hours and not storing the newest refresh token.

I will be the fist to admit that i am not the best at python but i cant see anywhere in your code that you are storing the token.

The most common cause for the invalid_grant error is that your refresh token has expired.

here is my youtube API auth and refresh function for tokens.. I've been using this for about a week now with zero issues

def youtube_auth(self):
    """ Loading / Getting Youtube Credentials"""
    creds = None
    
    if os.path.exists('token_youtube.json'):
        creds = Credentials.from_authorized_user_file('token_youtube.json', SCOPES)
        
    elif not os.path.exists('token_youtube.json'):
        
        self.create_token_file()
        creds = Credentials.from_authorized_user_file('token_youtube.json', SCOPES)
        
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:

            flow = InstalledAppFlow.from_client_config(CLIENT_SECRET, SCOPES)

           # creds = flow.run_console()
            creds = flow.run_local_server(port=0)


        """Save credentials"""
        with open('token_youtube.json', 'w') as f:
            f.write(creds.to_json())


    self.youtube = googleapiclient.discovery.build(API_SERVICE_NAME,
                                                   API_VERSION,
                                                   credentials=creds,
                                                   static_discovery=False)  
Related