使用Google Forms API获取表单响应时遇403权限不足错误求助
错误信息
调用Google Forms API获取表单响应时触发以下403错误:
Error: { "error": { "code": 403, "message": "Request had insufficient authentication scopes.", "errors": [ { "message": "Insufficient Permission", "domain": "global", "reason": "insufficientPermissions" } ], "status": "PERMISSION_DENIED", "details": [ { "@type": "type.googleapis.com/google.rpc.ErrorInfo", "reason": "ACCESS_TOKEN_SCOPE_INSUFFICIENT", "domain": "googleapis.com", "metadata": { "service": "forms.googleapis.com", "method": "google.apps.forms.v1.FormsService.ListFormResponses" } } ] } }
已验证的正常功能:Drive API调用成功
已通过Drive API实现文件列表获取,相关代码如下:
apiDrive.php
<?php require_once "/Users/xxxxx/Php/GoogleApis/apiclient/vendor/autoload.php"; session_start(); $clientSecretFile = "C:\Users\xxxxx\Php\Certificates\oAuth2\client_secret.json"; $client = new Google\Client(); $client->setAuthConfig($clientSecretFile); $client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY); if (isset($_SESSION['access_token']) && $_SESSION['access_token']) { $client->setAccessToken($_SESSION['access_token']); $drive = new Google\Service\Drive($client); $files = $drive->files->listFiles(array()); if (count($files->getFiles()) == 0) { print "No files found.\n"; } else { foreach ($files->getFiles() as $file) { $res['name'] = $file->getName(); $res['id'] = $file->getId(); $files[] = $res; } print_r($files); } } else { $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php'; header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL)); } ?>
oauth2callback.php
<?php require_once "/Users/xxxxx/Php/GoogleApis/apiclient/vendor/autoload.php"; session_start(); use Google\Client; use Google\Service\Exception; $clientSecretFile = "C:\Users\xxxxx\Php\Certificates\oAuth2\client_secret.json"; $client = new Google\Client(); $client->setAuthConfigFile($clientSecretFile); $client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php'); $client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY); if (! isset($_GET['code'])) { $auth_url = $client->createAuthUrl(); header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL)); } else { $client->authenticate($_GET['code']); $_SESSION['access_token'] = $client->getAccessToken(); $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/'; header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL)); } ?>
启动PHP内置服务器后,访问localhost:80/apiDrive.php可正常获取Drive文件列表,OAuth2流程正常(仅令牌过期时需清除会话)。
问题场景:Forms API调用失败
尝试调用Forms API时触发权限错误,相关代码如下:
apiForm.php
<?php require_once "/Users/xxxxx/Php/GoogleApis/apiclient/vendor/autoload.php"; session_start(); use Google\Client; use Google\Service\Forms; use Google\Service\Exception; $clientSecretFile = "C:\Users\xxxxx\Php\Certificates\oAuth2\client_secret.json"; $client = new Google\Client(); $client->setApplicationName('Google Forms API PHP'); $client->setScopes(['https://www.googleapis.com/auth/forms.responses.readonly']); $client->setAuthConfig($clientSecretFile); if (isset($_SESSION['access_token']) && $_SESSION['access_token']) { $client->setAccessToken($_SESSION['access_token']); $service = new Forms($client); $formId = "xxxxxxxxx"; try { $responses = $service->forms_responses->listFormsResponses($formId); echo $responses; } catch (Exception $e) { echo 'Error: ' . $e->getMessage(); } } else { $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php'; header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL)); } ?>
使用的oauth2callback.php与Drive API版本一致,错误在执行$service = new Forms($client);时触发,尚未传入formId。
解决方案
更新OAuth回调文件的权限范围
当前oauth2callback.php仅添加了Drive的只读元数据权限,需要同时包含Forms响应只读权限。修改oauth2callback.php中的权限设置:// 替换原addScope行 $client->addScope([ Google\Service\Drive::DRIVE_METADATA_READONLY, 'https://www.googleapis.com/auth/forms.responses.readonly' ]);清除旧的会话令牌
由于之前的令牌仅包含Drive权限,需要清除服务器端的会话(删除$_SESSION['access_token']),或直接清除浏览器Cookie,重新走OAuth授权流程,获取包含Forms权限的新令牌。验证Forms API已启用
登录Google Cloud控制台,确认Forms API已在项目中启用(搜索Forms API,确保状态为“已启用”)。检查表单权限
确保当前授权的Google账号对目标表单拥有查看响应的权限(表单所有者或已被授予响应查看权限)。
内容的提问来源于stack exchange,提问作者Philaupatte

