While working with the Python googleapiclient module, I am noticing some interesting behavior that I have not been able to track down.
The Issue:
When I receive a user's credentials from Google after successfully following the OAuth2.0 flow, I am able to programmatically create a secondary calendar for the user and add events to that calendar. After these credentials expire, I am able to refresh the credentials using the offline/refresh token and can continue to lookup and add more events to the secondary calendar that was created. However, I am no longer able to create any additional secondary calendars after the credentials have been refreshed. When I attempt to do so, I receive the following error:
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/calendar/v3/calendars?alt=json returned "Request had insufficient authentication scopes.">
The authorization scopes that I am using throughout the entire process are:
SCOPES = ['https://www.googleapis.com/auth/calendar.app.created',
'https://www.googleapis.com/auth/calendar.calendarlist.readonly']
If, after receiving this error, I then have the user successfully go through the OAuth2.0 flow again, I am able to use those credentials to create another secondary calendar as expected. That being said, this is not ideal for my application as the user's credentials expire after a few hours and it will often be days before the application needs to create new events/calendars.
Troubleshooting:
I have tried passing my developer key to the googleapiclient.discovery.build function in addition to the user's credentials to give it an additional authentication method, however when I do, I then receive the following error:
googleapiclient.errors.HttpError: <HttpError 401 when requesting https://www.googleapis.com/calendar/v3/calendars?key=[REDACTED]&alt=json returned "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.">
Researching this issue, I have found a number of sources that suggest deleting the token.pickle and refreshing the credentials.json and running through the process again. I do not use either of these files but instead store the pickled data in a DB and keep the app credentials in the environment. I have cleared out the user's credentials and made sure that my app credentials are correct.
Coding Example:
# Check to see if the credentials have expired
if not client_creds.valid:
# If the credentials are expired and can be refreshed,
# then refresh the credentials
if client_creds.expired and client_creds.refresh_token:
client_creds.refresh(Request())
retStatus = 0
# Use the refreshed credentials to build a Google Calendar v3 service
service = build("calendar", "v3",
credentials=client_creds,
developerKey=os.environ["GCAL_APIKEY"])
# Create a body for the new calendar
newCalBody = {
"summary": "Example Summary",
"description": "Example Description"
}
# Attempt to create the secondary calendar for the user
created_calendar = service.calendars().insert(body=newCalBody).execute()
# At this step, the 40x error will occur
Any help would be appreciated! Thanks in advance!
