pygsheets
pygsheets copied to clipboard
Issues with Maintaining Authentication
I have an application that's periodically ran via a cron job in order to read and write data to some Google Sheets. The application works fine for a little over a week or two at a time, then it will crash with this stack trace:
Traceback (most recent call last):
File "main.py", line 137, in <module>
remove_old_jobs(args.delete[0])
File "main.py", line 26, in remove_old_jobs
master_sheet = MasterGoogleSheet(master_sheet_id)
File "/home/ec2-user/python/zapier-social-media/misc_utils/master_google_sheet.py", line 14, in __init__
google_sheets_access = pygsheets.authorize()
File "/home/ec2-user/python/zapier-social-media/venv/lib/python3.6/site-packages/pygsheets/authorization.py", line 129, in authorize
credentials = _get_user_authentication_credentials(client_secret, scopes, credentials_directory, local)
File "/home/ec2-user/python/zapier-social-media/venv/lib/python3.6/site-packages/pygsheets/authorization.py", line 40, in _get_user_authentication_credentials
credentials.refresh(Request())
File "/home/ec2-user/python/zapier-social-media/venv/lib/python3.6/site-packages/google/oauth2/credentials.py", line 214, in refresh
scopes,
File "/home/ec2-user/python/zapier-social-media/venv/lib/python3.6/site-packages/google/oauth2/_client.py", line 248, in refresh_grant
response_data = _token_endpoint_request(request, token_uri, body)
File "/home/ec2-user/python/zapier-social-media/venv/lib/python3.6/site-packages/google/oauth2/_client.py", line 124, in _token_endpoint_request
_handle_error_response(response_body)
File "/home/ec2-user/python/zapier-social-media/venv/lib/python3.6/site-packages/google/oauth2/_client.py", line 60, in _handle_error_response
raise exceptions.RefreshError(error_details, response_body)
google.auth.exceptions.RefreshError: ('invalid_grant: Token has been expired or revoked.', '{\n "error": "invalid_grant",\n "error_description": "Token has been expired or revoked."\n}')
According to this Stack Overflow post, this may occur when an application asks for the Refresh Token more times than necessary, leading to the stored ones being expired. This may be occurring in the pygsheets.authorize() method. However, I don't know that this is necessarily the issue (which is why I was hesitant to mark this as a bug).
Is there a way I can keep from having to occasionally go back through the authentication process? I was thinking about redesigning the application so that it just runs in the background. That way, the authorize function only needs to be called once (when the application is launched) instead of needing to be called everytime the application is ran. However, I'd rather not have to do that unless necessary.
how many times (approx) does the script runs before it fails auth?
I'd say a little over 200 times. However, looking back at my code, it calls the authorize function a few times throughout each run, cause I created an object to encapsulate Sheets and the specific operations I want to perform on each of them and the init function of those objects call the authorize function to get a Client object in order to get the Spreadsheet object. A better way would be to pass the Client object into the init function and only get one Client at main. Even still, that'll only extend the length of time between manual re-authorizations.
any solutions to this? i have the exact same issue @rstone13 @nithinmurali
Using Authlib instead of google-auth might help resolve this. (using AssertionSession) This might need some changes in library code. ref
This is preventing me from accessing my sheets. From what I have read it is associated with the Oauth shift from 1.29 to 1.30. Are code changes required in pygsheets to accommodate this?
I too am getting this error: google.auth.exceptions.RefreshError: ('invalid_grant: Bad Request', '{\n "error": "invalid_grant",\n "error_description": "Bad Request"\n}')
Please advise! :(
There are no code changes for updating the library since there is no version pinning. I am unable to reproduce this, you can try deleting your existing credentials and try again.
As for auto auth refreshing, you can try using this snippet which uses authlib
import json
from authlib.integrations.requests_client import AssertionSession
def create_assertion_session(conf_file, scopes, subject=None):
with open(conf_file, 'r') as f:
conf = json.load(f)
token_url = conf['token_uri']
issuer = conf['client_email']
key = conf['private_key']
key_id = conf.get('private_key_id')
header = {'alg': 'RS256'}
if key_id:
header['kid'] = key_id
# Google puts scope in payload
claims = {'scope': ' '.join(scopes)}
return AssertionSession(
grant_type=AssertionSession.JWT_BEARER_GRANT_TYPE,
token_url=token_url,
issuer=issuer,
audience=token_url,
claims=claims,
subject=subject,
key=key,
header=header,
)
scopes = [
'https://www.googleapis.com/auth/spreadsheets',
'https://www.googleapis.com/auth/drive',
]
session = create_assertion_session('your-google-conf.json', scopes)
gc = Client(None, http=session)
Huh! Yeah I tried replacing creds, no luck. I then started from scratch with new gcp project and hit the same issue, that was unexpected. Here is the response:
Traceback (most recent call last):
File "C:/Users/test/gsheets_pull_r0.py", line 34, in
you are facing this issue when the script if running for long time right? you can access sheets initially but after some time when the token expires, this error happens?
I ran into the same issue. For me, deleting the local sheets.googleapis.com-python.json
file, running my script again, and reauthenticating through the printed URL fixed things.