集成Play Integrity API与GoogleAuth时遭遇403 Forbidden错误排查
问题:Play Integrity API后端解码返回403 Forbidden
已将Android应用部署到内部测试环境,Play Console配置完成,Android端能正常获取Integrity Token,但后端用Node.js通过GoogleAuth调用decodeIntegrityToken接口时,虽能拿到token和accessToken,却返回403 Forbidden错误。已完成Cloud项目关联、API启用、服务账号JSON配置,求排查缺失的配置步骤。
Android端代码
val integrityTokenResponse = integrityTokenProvider.request( StandardIntegrityTokenRequest.builder() .setRequestHash(hash) .build() ) integrityTokenResponse.addOnSuccessListener { response -> lifecycleScope.launch { val apiResponse = retrofit.verifyHash(VerifyHashRequest(response.token())) runOnUiThread { textView.text = apiResponse.message } } }.addOnFailureListener { exception -> Toast.makeText(this@MainActivity,"Failure ${exception.message}",Toast.LENGTH_LONG).show() }
后端Node.js代码
import { GoogleAuth } from "google-auth-library"; import path from "path"; const { token, }: { token: string; } = await request.json(); const keyFilePath = path.resolve( "./my.json" ); const auth = new GoogleAuth({ keyFile: keyFilePath, scopes: ["https://www.googleapis.com/auth/playintegrity"], }); const packageName = "myandroidpackagename"; const client = await auth.getClient(); const accessToken = await client.getAccessToken(); const url = `https://playintegrity.googleapis.com/v1/${packageName}:decodeIntegrityToken`; console.log("token", token); console.log("accessToken", accessToken.token); const response = await fetch(url, { method: "POST", headers: { Authorization: `Bearer ${accessToken.token}`, "Content-Type": "application/json", }, body: JSON.stringify({ integrityToken: token, }), }); console.log("response", response); if (!response.ok) { throw new Error(response.statusText); } const json = await response.json(); return Response.json({ message: JSON.stringify(json), }); } catch (e) { return Response.json({ message: "Error " + e, }); }
错误响应
{ status: 403, statusText: 'Forbidden', headers: Headers { vary: 'Origin, X-Origin, Referer', 'content-type': 'application/json; charset=UTF-8', date: 'Sun, 29 Dec 2024 08:19:31 GMT', server: 'ESF', 'content-length': '154', 'x-xss-protection': '0', 'x-frame-options': 'SAMEORIGIN', 'x-content-type-options': 'nosniff', 'alt-svc': 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000' }, body: ReadableStream { locked: false, state: 'readable', supportsBYOB: true }, bodyUsed: false, ok: false, redirected: false, type: 'basic', url: 'https://playintegrity.googleapis.com/v1/myapppackage:decodeIntegrityToken' }
缺失的配置步骤排查
- 给服务账号分配Play Integrity API 解码器角色
进入Google Play Console,找到目标应用 → 开发者账号 → API访问 → 找到关联的服务账号,点击「授予访问权限」,添加「Play Integrity API 解码器」角色(该角色是解码Integrity Token的必备权限)。 - 确认服务账号所属Cloud项目与Play Console绑定项目一致
检查Play Console中API访问页面显示的Cloud项目ID,和服务账号JSON文件里的project_id是否完全匹配,项目不匹配会导致权限验证失败。 - 验证内部测试账号与版本状态
确保获取Token的设备所用Google账号已加入内部测试授权列表,且应用的内部测试版本已完成发布(非草稿状态),未发布或未授权的测试版本生成的Token无法被正常解码。 - 检查包名完全匹配
后端代码中的packageName必须和Android应用的包名完全一致,包括大小写(Android包名通常为小写,但严格匹配是必要的)。 - 重新确认服务账号JSON文件有效性
重新下载服务账号的JSON密钥文件,确保文件未被修改,其中的client_email和project_id与对应项目信息一致。
内容的提问来源于stack exchange,提问作者BraveEvidence
相关产品推荐
相关产品推荐

