I'm using Google's python quickstart script from here: https://developers.google.com/calendar/quickstart/python
It works great under normal circumstances. I can allow it access to my Gmail account, and it can create Google Calendar entries.
If I login to my Gmail account in a browser however, go to Security, and revoke my app's access to my Google account, the quickstart script doesn't pick up on it. It just crashes:
$ python quickstart.py
Getting the upcoming 10 events
Traceback (most recent call last):
File "quickstart.py", line 52, in <module>
main()
File "quickstart.py", line 42, in main
orderBy='startTime').execute()
File "/opt/my_project/venv3/lib/python3.6/site-packages/googleapiclient/_helpers.py", line 130, in positional_wrapper
return wrapped(*args, **kwargs)
File "/opt/my_project/venv3/lib/python3.6/site-packages/googleapiclient/http.py", line 851, in execute
method=str(self.method), body=self.body, headers=self.headers)
File "/opt/my_project/venv3/lib/python3.6/site-packages/googleapiclient/http.py", line 165, in _retry_request
resp, content = http.request(uri, method, *args, **kwargs)
File "/opt/my_project/venv3/lib/python3.6/site-packages/google_auth_httplib2.py", line 213, in request
self.credentials.refresh(self._request)
File "/opt/my_project/venv3/lib/python3.6/site-packages/google/oauth2/credentials.py", line 136, in refresh
self._client_secret))
File "/opt/my_project/venv3/lib/python3.6/site-packages/google/oauth2/_client.py", line 237, in refresh_grant
response_data = _token_endpoint_request(request, token_uri, body)
File "/opt/my_project/venv3/lib/python3.6/site-packages/google/oauth2/_client.py", line 111, in _token_endpoint_request
_handle_error_response(response_body)
File "/opt/my_project/venv3/lib/python3.6/site-packages/google/oauth2/_client.py", line 61, in _handle_error_response
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}')
If I add some debug lines just before the line that throws the exception, I see this:
creds.valid: True
creds.expired: False
I know I can just catch google.auth.exceptions.RefreshError. The problem I have is that there's an entire section of code at the beginning of quickstart.py whose purpose is to detect that the token is valid, but it appears to fail to detect this fairly simple scenario, and the exception isn't thrown until I actually try to use the token to execute a command. Putting every single execute (or at least the first one) in a try-except block in case the first part of the script couldn't do its job in detecting that the token is revoked seems dumb.
Is there a way to detect that the certificate was revoked before I actually try to use it? Why doesn't creds.valid and creds.expired work?
Update: It looks like if you wait long enough (a few minutes or hours - not sure), creds.valid and creds.expired will eventually show that the credentials are no longer valid. This time in between however, when the credentials appear to be valid, but can't be used, is enough to make my program crash if I don't handle it correctly.
Update 2: The only thing I can think of is to just run something like:
from googleapiclient.discovery import build
from google.auth.exceptions import RefreshError
...
try:
service = build('calendar', 'v3', credentials=creds)
service.events().list(calendarId='primary', maxResults=1).execute()
except RefreshError:
...
...
right after the code that checks if the credentials are valid. Sort of like a final check. This works, but seems a bit dirty, as it requires an extra call to the Google API servers, and is basically exactly what I said above - putting the first execute in a try-except block. Is there no better way?