已授权全域委派的服务账号在Cloud Function调用Admin SDK时遇403错误
问题:配置Google Workspace全域委派的服务账号调用Admin SDK时触发403权限错误
问题描述
配置了Google Workspace全域委派的服务账号,在GCP Cloud Function中调用已授权范围的Admin SDK时,持续收到「Not Authorized to access this resource/api」403权限错误。
环境与配置
- Cloud Function配置:
Service account: my-domain-wide-delegation-enabled-serviceaccount@my-gcp-project-name.iam.gserviceaccount.com Build service account: my-project-default-service-account@appspot.gserviceaccount.com - 已在Google Workspace的「Security > API Controls > Domain-wide Delegation」中,为该服务账号的OAuth 2 Client ID授权以下范围:
https://www.googleapis.com/auth/admin.directory.user https://www.googleapis.com/auth/admin.directory.group https://www.googleapis.com/auth/gmail.send - Cloud Function核心代码:
辅助函数获取Workspace凭证:
入口函数调用Admin SDK:const SCOPES = [ 'https://www.googleapis.com/auth/admin.directory.user', 'https://www.googleapis.com/auth/admin.directory.group', 'https://www.googleapis.com/auth/gmail.send' ]; async function getWorkspaceCredentials() { try { console.log("获取Workspace凭证..."); const auth = new google.auth.GoogleAuth({ scopes: SCOPES }); // 获取源凭证 console.log("获取客户端..."); const client = await auth.getClient(); console.debug("客户端信息: ", { email: client.email, // 服务账号邮箱 scopes: client.scopes // 实际使用的范围 }); const email = await auth.getCredentials(); console.debug("服务账号详情: ", { email: email.client_email, project_id: email.project_id, type: email.type }); console.log("设置客户端主体(要模拟的管理员用户)...") client.subject = 'testadminaccount@mydomain.com'; const token = await client.getAccessToken(); console.debug("成功获取测试访问令牌: ", token.token.substring(0,10) + "..."); console.log("Workspace凭证获取成功。"); return client; } catch (error) { console.error('获取Workspace凭证失败:', error); throw error; } }functions.http('createNewWorkspaceAccount', async (req, res) => { // 获取Workspace凭证并创建Admin服务 const auth = await getWorkspaceCredentials(); console.debug("auth凭证: ", auth); const admin = google.admin({ version: 'directory_v1', auth }); console.debug("基于auth凭证创建的Admin服务: ", admin); // 调试测试 const testList = await admin.users.list({ domain: 'mydomain.com', maxResults: 1 }); console.debug("测试列表响应: ", testList.data); console.debug("查询已知测试用户的Admin数据: ", await admin.users.get({userKey: "testuser@mydomain.com"})); });
错误详情
执行到admin.users.list()时触发403错误,完整错误信息:
GaxiosError: Not Authorized to access this resource/api at Gaxios._request (/workspace/node_modules/googleapis-common/node_modules/gaxios/build/src/gaxios.js:129:23) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async Compute.requestAsync (/workspace/node_modules/googleapis-common/node_modules/google-auth-library/build/src/auth/oauth2client.js:368:18) at async /workspace/index.js:236:22 { response: { config: { url: 'https://admin.googleapis.com/admin/directory/v1/users?domain=mydomain.com&maxResults=1', method: 'GET', userAgentDirectives: [Array], paramsSerializer: [Function (anonymous)], headers: [Object], params: [Object], validateStatus: [Function (anonymous)], retry: true, responseType: 'json', retryConfig: [Object] }, data: { error: [Object] }, headers: { 'alt-svc': 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000', 'content-encoding': 'gzip', 'content-type': 'application/json; charset=UTF-8', date: 'Tue, 14 Jan 2025 21:28:50 GMT', server: 'ESF', 'transfer-encoding': 'chunked', vary: 'Origin, X-Origin, Referer', 'x-content-type-options': 'nosniff', 'x-frame-options': 'SAMEORIGIN', 'x-xss-protection': '0' }, status: 403, statusText: 'Forbidden', request: { responseURL: 'https://admin.googleapis.com/admin/directory/v1/users?domain=mydomain.com&maxResults=1' } }, config: { url: 'https://admin.googleapis.com/admin/directory/v1/users?domain=mydomain.com&maxResults=1', method: 'GET', userAgentDirectives: [ [Object] ], paramsSerializer: [Function (anonymous)], headers: { 'x-goog-api-client': 'gdcl/5.1.0 gl-node/20.18.1 auth/7.14.1', 'Accept-Encoding': 'gzip', 'User-Agent': 'google-api-nodejs-client/5.1.0 (gzip)', Authorization: 'Bearer qwertyqwertyqwerty', Accept: 'application/json' }, params: { domain: 'mydomain.com', maxResults: 1 }, validateStatus: [Function (anonymous)], retry: true, responseType: 'json', retryConfig: { currentRetryAttempt: 0, retry: 3, httpMethodsToRetry: [Array], noResponseRetries: 2, statusCodesToRetry: [Array] } }, code: 403, errors: [ { message: 'Not Authorized to access this resource/api', domain: 'global', reason: 'forbidden' } ] }
已排查事项
- 确认GCP中服务账号的OAuth 2 Client ID与Workspace全域委派中的ID一致
- 验证
testadminaccount@mydomain.com为超级管理员,具备Workspace用户管理权限 - 尝试重新添加全域委派权限、为服务账号赋予GCP项目Owner角色,均未解决问题
- 已启用Admin SDK API
内容的提问来源于stack exchange,提问作者lampShadesDrifter
相关产品推荐
相关产品推荐

