4adelaar
4adelaar

Reputation: 53

Google Calendar API: Error code 403: The request is missing a valid API key

Recently I started playing around within Google's Calendar API in order to make a personal app for myself that would randomly create daily highlights and then make events out of them before passing it to my google calendar. I have very little experience with this sort of thing, almost none, but google's Quickstart guide got me set up in a decent place. I pretty much just took the Quickstart python code that they provided, added some of my own functions for making and deleting the events and adjusted the scope to include the permissions for creating and deleting said events. The code that I used:

from __future__ import print_function

import datetime
from hashlib import new
import os.path
from re import S

from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError

from highlightsGenerator import *

# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/calendar.readonly',
          'https://www.googleapis.com/auth/calendar.events',
          'https://www.googleapis.com/auth/calendar']

templateEvent = {
                'summary': 'Daily Highlight',
                'description': '',
                'start': {
                    'dateTime': '',
                    },
                'end': {
                    'dateTime': '',
                    },
                'reminders': {
                    'useDefault': True,
                    },
            }

def createHighlightEvents(service):
    workingDate = datetime.date.today()
    workingDate += datetime.timedelta(days=1)
    highlightSchedule = scheduleGenerator()
    print(highlightSchedule)
    for k in highlightSchedule:
        newEvent = templateEvent
        newEvent['description'] = k
        newEvent['start']['dateTime'] = str(workingDate) + 'T13:00:00+3:00'
        newEvent['end']['dateTime'] = str(workingDate) + 'T17:00:00+03:00'
        service.events().insert(calendarId='primary', body=newEvent).execute()
        workingDate += datetime.timedelta(days=1)

def deleteHighlightEvents(service):
    now = datetime.datetime.utcnow().isoformat() + 'Z'  # 'Z' indicates UTC time
    events_result = service.events().list(calendarId='primary', q='Daily Highlight',timeMin=now,
                                        maxResults=20, singleEvents=True,
                                        orderBy='startTime').execute()
    events = events_result.get('items', [])

    # if not events:
    #         print('No upcoming events found.')
    #         return

    for event in events:
        eID = event['id']
        service.events().delete(calendarId='primary', eventId=eID).execute()

def reRollHighlightEvents(service):
    deleteHighlightEvents(service)
    createHighlightEvents(service)

def getDate(dateTime):
    dateStr = dateTime[:len(dateTime) - 6]
    date = datetime.datetime.strptime(dateStr, '%Y-%m-%dT%H:%M:%S')
    return date

def shiftHighlights(service, numDays):
    now = datetime.datetime.utcnow().isoformat() + 'Z'  # 'Z' indicates UTC time
    events_result = service.events().list(calendarId='primary', q='Daily Highlight',timeMin=now,
                                        maxResults=20, singleEvents=True,
                                        orderBy='startTime').execute()
    events = events_result.get('items', [])

    if not events:
            print('No upcoming events found.')
            return
    
    for event in events:
        newStartDate = getDate(event['start']['dateTime']) + datetime.timedelta(days=numDays)
        newEndDate = getDate(event['end']['dateTime']) + datetime.timedelta(days=numDays)
        newStartDateStr = 'T'.join([str(newStartDate.date()), str(newStartDate.time())])
        newEndDateStr = 'T'.join([str(newEndDate.date()), str(newEndDate.time())])
        newEvent = event
        newEvent['start']['dateTime'] = newStartDateStr + '+03:00'
        newEvent['end']['dateTime'] = newEndDateStr + '+03:00'

        service.events().update(calendarId='primary', eventId=event['id'], body=newEvent).execute()
        


def main():
    """Shows basic usage of the Google Calendar API.
    Prints the start and name of the next 10 events on the user's calendar.
    """
    creds = None
    # The file token.json stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
   # If there are no (valid) credentials available, let the user log in.
    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(
                'client_secret_158794507060-ucqbqgapmlf7lmvre6knjc5nehd00ms0.apps.googleusercontent.com.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.json', 'w') as token:
            token.write(creds.to_json())

    try:
        service = build('calendar', 'v3', credentials=creds)

        # Call the Calendar API
        now = datetime.datetime.utcnow().isoformat() + 'Z'  # 'Z' indicates UTC time
        print('Getting the upcoming 10 events')
        events_result = service.events().list(calendarId='primary', timeMin=now,
                                              maxResults=10, singleEvents=True,
                                              orderBy='startTime').execute()
        events = events_result.get('items', [])

        if not events:
            print('No upcoming events found.')
            return

        # Prints the start and name of the next 10 events
        for event in events:
            start = event['start'].get('dateTime', event['start'].get('date'))
            print(start, event['summary'])

        userInput = input('Create (c), Delete (d), Re-Roll (r), Shift (s) highlights?\n')
        if userInput == 'c':
            createHighlightEvents(service)
        elif userInput == 'd':
            deleteHighlightEvents(service)
        elif userInput == 'r':
            reRollHighlightEvents(service)
        elif userInput == 's':
            numDays = input('How many days would you like to shift by?  (x) to cancel\n')
            if numDays != 'x' and numDays.isnumeric:
                shiftHighlights(service, int(numDays))
            elif numDays != 'x':
                print('Please input a number or (x) to cancel')
        else:
            print('That is not one of the options')

    except HttpError as error:
        print('An error occurred: %s' % error)


if __name__ == '__main__':
    main()

I managed to get it to do what I wanted and for a bit that was basically it, but then when I tried running it yesterday it gave a http 400 error for a bad request. Clicking the link it provided gave me this:

{
  "error": {
    "code": 403,
    "message": "The request is missing a valid API key.",
    "errors": [
      {
        "message": "The request is missing a valid API key.",
        "domain": "global",
        "reason": "forbidden"
      }
    ],
    "status": "PERMISSION_DENIED"
  }
}

Now as you may have seen I left in the code for retrieving and displaying the first 10 upcoming events. It is still able to run that just fine, but If attempt to create an event or delete an event then this error message shows up. I am quite confused by this message as I have done all the authorisation that I believed I needed to. My client secret has not changed, but even then I re-downloaded it to see if that would do anything, but it did not. I deleted the token and had it run the authorisation again and again I gave permission. This also proved fruitless and as far as I'm aware my scopes are fine.

There were a couple questions on here with similar errors, but they seemed to be getting it for different reasons than me (from what I could tell) or because they were missing an authorisation that I believe I already have.

Again, I have almost no experience with this sort of thing, so there may be something incredibly obvious that I am not doing, but I'm afraid I don't really know what that may be.

Any assistance you can provide would be much appreciated

Upvotes: 3

Views: 3453

Answers (3)

Arjun Raj
Arjun Raj

Reputation: 1

actually the same error come with my code and i changes the code of datetime then also give me same error what i can do to resolved the issue regrading this'' and this is my code--> def create_events(self): start_date = datetime.datetime(2023,1,5,18,30,0,0).isoformat()+'Z' end_date = datetime.datetime(2023,1,5,18,45,0,0).isoformat()+'Z'

    calendar_Id = '[email protected]'
    hours_adjustment = -8
    events_request_body = {
        'start':{
            'dateTime':start_date,
            'timeZone':'Asia/kolkata'
        },
        'end':{
            'dateTime':end_date,
            'timeZone': 'Asia/kolkata'
        },
    }
    calendar = service.events().insert(calendarId=calendar_Id,
                                       body=events_request_body,).execute()
    return calendar

how i can resolved the error and phase the error with in 3 days ... and i am very ferstated

Upvotes: 0

rwreed
rwreed

Reputation: 348

This may not help anyone else, but it was the solution for me. It may be what @Oriol Castander was getting at. I kept getting 403 errors saying missing an API key. But that was, for me, a false error. The actual problem was the date I was using. in the events().list command. I was using an exact date (June 4, 2022) rather than now() and I needed to format it as follows:

date=datetime.datetime(2022, 6, 4,0,0,0,0).isoformat() + 'Z'

Once I had the date correctly formatted the call ran without error.

Upvotes: 2

Oriol Castander
Oriol Castander

Reputation: 648

I have recreated and run your code and I could not bump into the 403. The code looks fine and it should work, especially since you can retrieve the data with a list command. This is not a definitive answer, but to get it to work you could try:

  • Redownloading the credentials.json file after disabling and enabling the Calendar API.
  • Only using the 'https://www.googleapis.com/auth/calendar' scope, since is the least restrictive one and the one needed to create an event.
  • Deleting the token.json file to force OAuth to sign you in again.

Nevertheless, I did manage to find an error that will cause your code to fail when you get it up and running. The 'start' and 'end' properties need both a 'dateTime' and a 'timeZone' property as it is done in this example. Therefore this code will fail:

newEvent['start']['dateTime'] = str(workingDate) + 'T13:00:00+3:00'
newEvent['end']['dateTime'] = str(workingDate) + 'T17:00:00+03:00'

and should be replace with this one:

newEvent['start']['dateTime'] = str(workingDate) + 'T13:00:00'
newEvent['start']['timeZone'] = 'Your timeZone'
newEvent['end']['dateTime'] = str(workingDate) + 'T17:00:00'#Having the +3:00 will fail
newEvent['end']['timeZone'] = 'Your timeZone'

And you can find your timeZone in, of course, Wikipedia: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones

Upvotes: 2

Related Questions