调用Google People API时服务账号获取access token未授权报错问题
Google People API服务端调用报错排查
我正在为Web应用测试Google People API,操作步骤如下:
- 我在Google控制台(https://console.cloud.google.com/)创建了新项目
- 我启用了People API
- 我创建了所需凭据:应用对应的Web客户端和API key
- 我创建了带p12密钥的service account用于服务端间查询,同时开启了“Google Workspace Domain-wide Delegation”
- 我配置了OAuth consent screen,设置了向Google授权并访问People API所需的scope:
/auth/userinfo.email、/auth/userinfo.profile、/auth/contacts、/auth/contacts.readonly - 随后我使用“Google API PHP client”编写PHP脚本,生成指向同意屏幕的跳转链接,通过Web客户端获取用于换取access token的授权码:
<?php $client = new Google_Client(); $client->setAccessType('online'); // default: offline $client->setApplicationName('My Project xxxxx'); $client->setClientId('999999999999-qwertysdfhwe9uriiiiiiiiiiiiiiiii.apps.googleusercontent.com'); $client->setClientSecret('GOCSPX-hhhhhhhhhhhhhhhhhhhhhhhhhhhh'); $client->setDeveloperKey('AIzafffffffffffffffffffffffffffffffffff'); // API key $client->setState('subdomain.myapp.com'); $scriptUri = 'https://oauth.myapp.com/auth.php'; $client->setRedirectUri($scriptUri); $client->addScope('https://www.googleapis.com/auth/userinfo.email'); $client->addScope('https://www.googleapis.com/auth/userinfo.profile'); $client->addScope('https://www.googleapis.com/auth/contacts'); $auth_url = $client->createAuthUrl(); header('Location: '.$auth_url); ?>
上述代码会跳转到Google身份验证页面,我登录Google账号并同意授权scope后,Google会重定向回我的应用,此时我已获取到access token、已授权scope列表以及已认证用户的邮箱。
后续步骤我遇到了无法解决的问题:通过服务端间查询的方式获取People API的access token时失败,相关代码如下:
function base64_url_encode($input) { return str_replace('=', '', strtr(base64_encode($input), '+/', '-_')); } $iat = time(); $url = "https://www.googleapis.com/oauth2/v4/token"; $scope = 'https://www.googleapis.com/auth/contacts'; $jwt_data = array( 'iss' => '111111111111111111111', // My service account ID 'aud' => $url, 'scope' => $scope, 'exp' => $iat + 3600, 'iat' => $iat, 'sub' => 'user@gmail.com', // Email of the user that was autenticated in first step ); openssl_pkcs12_read(file_get_contents('keyfile.p12'), $certs, 'notasecret'); $header = array('typ' => 'JWT', 'alg' => 'RS256'); $signing_input = base64_url_encode(json_encode($header)) . '.' . base64_url_encode(json_encode($jwt_data)); openssl_sign($signing_input, $signature, $certs['pkey'], 'SHA256'); $jwt = $signing_input . '.' . base64_url_encode($signature); $data = array( "grant_type" => "urn:ietf:params:oauth:grant-type:jwt-bearer", "assertion" => $jwt ); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 30); $response = curl_exec($ch); curl_close($ch); $google_contacts_api_tokens_collection[$use_mailbox] = $response; return $response;
运行上述代码后Google返回了我无法解决的错误,目前暂无排查思路,错误信息如下:
原错误内容:"Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested."
中文翻译:客户端无权使用此方法获取访问令牌,或客户端未获得所请求的任何范围的授权
解决方案
按优先级逐一排查即可:
- 确认使用场景匹配授权逻辑
你开启的Google Workspace全域委派仅对你自己企业域名下的账号生效,当前代码中sub字段填写的user@gmail.com是普通个人Google账号,不属于你的Workspace托管域,全域委派对个人账号完全无效,这类场景不需要用服务账号JWT流程,直接用第一步拿到的refresh token长期刷新access token调用接口即可。
如果确实需要用服务账号访问,必须确保sub字段填写的是你企业域名下的内部邮箱,不能填gmail后缀的个人账号。 - 检查Workspace域scope授权配置
如果是访问企业内部用户数据,需要进入Google Workspace管理后台的「API权限」->「全域委派权限」页面,找到对应服务账号的客户端ID,手动添加你用到的所有scope,保存后等待15分钟左右生效,未在此处添加的scope即使代码中请求也会被拒绝。 - 校验基础参数配置
确认JWT中iss字段填写的是服务账号的完整邮箱(格式为xxx@xxx.iam.gserviceaccount.com),不是你当前填写的纯数字服务账号ID,参数填错是常见触发原因。
内容的提问来源于stack exchange,提问作者Simon Z
相关产品推荐
相关产品推荐

