Python使用OAuth调用Google Calendar API报缺失API key的403错误
问题描述
使用OAuth认证方式通过Python官方SDK调用Google Calendar API时,返回403 PERMISSION_DENIED错误,错误响应如下:
{ "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" } }
已检索到JS场景下的同类问题解决方案:初始化服务实例时传入auth参数,示例代码如下:
google.calendar({ version: "v3", auth: client })
该方案不适用于Python SDK场景,Python SDK初始化服务时传入credentials参数,写法如下:
service = build('calendar', 'v3', credentials=creds)
现有代码除client_secret文件名外,与官方Quickstart示例完全一致,完整代码如下:
from __future__ import print_function import datetime import os.path 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 # If modifying these scopes, delete the file token.json. SCOPES = ['https://www.googleapis.com/auth/calendar.readonly'] 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_desktop.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']) except HttpError as error: print('An error occurred: %s' % error) if __name__ == '__main__': main()
初步判断问题出在Credentials配置环节,需要对应排查方向与解决方法。
排查与解决步骤
按优先级从高到低依次排查:
- 第一步:清除旧凭据缓存重新授权
直接删除脚本运行目录下的token.json文件,再重新运行脚本走完整授权流程。90%的同类问题都是修改了client_secret配置、调整了SCOPES范围后,没有删除旧的token缓存,导致请求携带的是无效的旧凭据,被服务端识别为未携带有效认证信息的匿名请求,才会提示缺少有效API key。 - 第二步:校验OAuth客户端类型与配置
代码里用的是InstalledAppFlow,对应Google Cloud控制台创建的OAuth客户端必须是**桌面应用(Desktop app)**类型,不能选Web应用、服务账号等其他类型,类型不匹配会导致生成的凭据结构不符合预期,无法被SDK正确识别传入请求头。同时确认下载的client_secret_desktop.json文件没有下载损坏、内容截断,文件路径和代码里的引用路径一致。 - 第三步:检查API启用状态与同意屏配置
进入Google Cloud控制台的「API和服务」页面,确认Google Calendar API已经正式启用,仅创建凭据不启用对应API时,所有请求都会被直接拦截返回权限错误。如果你的OAuth同意屏幕配置为外部用户类型,测试阶段必须把当前用来授权的谷歌账号添加到测试用户列表中,否则授权生成的凭据不具备访问权限。 - 第四步:修复SDK版本兼容问题
旧版本的Google API Python SDK存在credentials参数解析bug,会出现传了凭据但请求头没带认证信息的问题,先执行以下命令升级所有相关依赖到最新稳定版:
升级后可以在初始化service之前加两行调试代码,确认凭据有效:pip install --upgrade google-api-python-client google-auth google-auth-oauthlib
如果两个值有任意一个为False,说明凭据生成环节存在问题,回到第二步重新检查客户端配置。print(creds.valid) # 正常应该返回True print(bool(creds.token)) # 正常应该返回True
内容的提问来源于stack exchange,提问作者Sebinda
相关产品推荐
相关产品推荐

