验证Play Games服务器代码时遇unauthorized_client错误求助
我正在使用以下Cloud Function验证游戏发送的Play Games serverAuthToken:
const functions = require("firebase-functions"); const verifier = require("gamecenter-identity-verifier"); const {defineSecret} = require("firebase-functions/params"); const admin = require("firebase-admin"); const cors = require("cors")({origin: true}); const {google} = require("googleapis"); const serverClientId = defineSecret("SERVER_CLIENT_ID"); const serverClientSecret = defineSecret("SERVER_CLIENT_SECRET"); admin.initializeApp(); const auth = admin.auth(); const BUNDLE_ID = "com.bundle.id"; // 实际应用中为真实Bundle ID exports.pgAuth = functions .runWith({secrets: [serverClientId, serverClientSecret ]}) .https.onRequest((req, res) => { return cors(req, res, async () => { const oauth2Client = new google.auth.OAuth2( serverClientId.value(), serverClientSecret.value(), "https://oauth2.googleapis.com/token", ); await oauth2Client.getToken(req.body.code); const result = await auth.createCustomToken(req.body.playerId); res.json({result}); }); });
我使用的是已发布游戏中注册的服务器令牌,且已确认客户端ID、密钥及回调URI配置正确,但运行该Cloud Function时出现如下错误:
Error: unauthorized_client at Gaxios._request (/workspace/node_modules/googleapis-common/node_modules/gaxios/build/src/gaxios.js:130:23) at processTicksAndRejections (node:internal/process/task_queues:96:5) at async OAuth2Client.getTokenAsync (/workspace/node_modules/googleapis-common/node_modules/google-auth-library/build/src/auth/oauth2client.js:125:21) at async /workspace/index.js:30:9
这是我首次实现该流程,已验证ID和密钥正确,推测可能是客户端权限不足或使用了错误的Google库,恳请提供解决建议。
修正授权流程类型:
oauth2Client.getToken()是用于授权码流程的方法,但Play Games的serverAuthToken属于ID令牌,无需走授权码交换。你需要直接调用Google的令牌验证端点来校验token有效性,而非使用getToken()。确认OAuth客户端类型:确保在Google Cloud Console创建的是Web应用类型的OAuth客户端ID,Android/iOS客户端ID无法用于服务器端的ID令牌验证。
验证令牌受众匹配:serverAuthToken的
aud(受众)字段必须严格匹配你的服务器客户端ID。调用https://oauth2.googleapis.com/tokeninfo?id_token=YOUR_SERVER_AUTH_TOKEN接口,检查返回的aud值是否与SERVER_CLIENT_ID一致,不一致则说明客户端ID配置错误。调整代码逻辑:替换原有的
getToken()调用,改为直接验证ID令牌,示例代码如下:// 替换原oauth2Client.getToken(req.body.code)部分 const tokenInfo = await google.oauth2("v2").tokeninfo({ id_token: req.body.serverAuthToken // 注意参数是serverAuthToken而非code }); // 校验令牌受众 if (tokenInfo.aud !== serverClientId.value()) { return res.status(401).json({error: "Invalid token audience"}); } // 验证通过后生成自定义令牌,使用令牌中的sub作为playerId const result = await auth.createCustomToken(tokenInfo.sub);检查网络权限:如果Cloud Function配置了VPC限制,需确保允许访问
oauth2.googleapis.com域名,否则会出现请求失败或权限错误。
内容的提问来源于stack exchange,提问作者mikesol

