特定账号设备下GoogleAuth验证IDToken报错[No pem found]求助
特定设备+账号组合下Google SignIn idToken验证失败问题
场景说明
- Android应用(Kotlin+Jetpack Compose):通过GoogleSignIn获取账号idToken,发送至Node.js服务器验证
- Node.js服务器:调用
GoogleAuth.OAuth2Client.verifyIdToken()验证idToken
仅Device A(三星GS8,Android 9)+Account A+发布包+生产服务器组合出现失败,其余场景均正常:
- 虚拟机调试客户端→开发服务器:正常
- 虚拟机调试客户端→生产服务器:正常
- 虚拟机发布客户端→生产服务器:正常
- 物理机调试客户端→生产服务器(Account A+Device A):正常
- 物理机发布客户端→生产服务器:其他组合均正常
异常信息
Error: No pem found for envelope: {"alg":"RS256","kid":"4qa48u3nvj3498fru03984nmr20938yf7c63b4f8","typ":"JWT"} at OAuth2Client.verifySignedJwtWithCertsAsync (.../node_modules/google-auth-library/build/src/auth/oauth2client.js:608:19) at OAuth2Client.verifyIdTokenAsync (.../node_modules/google-auth-library/build/src/auth/oauth2client.js:444:34) at processTicksAndRejections (internal/process/task_queues.js:93:5) at async Object.VerifyIdToken (.../server_auth_file.js:666:18)
相关代码
客户端代码(仅收到500错误,无本地崩溃)
import ... class LoginActivity : ComponentActivity() { private lateinit var signinActivity: ActivityResultLauncher<Intent> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) signinActivity = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -> try{ val task = GoogleSignIn.getSignedInAccountFromIntent(result.data) handleSignInResult(task) } catch (err:ApiException){ // todo -- check error code against GoogleSignInStatusCodes val intent = Intent() intent.putExtra("success",false) intent.putExtra("message","cancelled") setResult(RESULT_CANCELED, intent) finish() } } signIn() } private fun getGoogleSignInClient(): GoogleSignInClient { val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken((this as Context).resources.getString(R.string.APP_CLIENT_ID)) .requestEmail() .build() return GoogleSignIn.getClient(this, gso) } private fun signIn() { val signInIntent = getGoogleSignInClient().signInIntent signinActivity.launch(signInIntent) } private fun handleSignInResult(completedTask: Task<GoogleSignInAccount>) { val accountData = completedTask.getResult( ApiException::class.java ) // refresh server access token val accessToken = refreshAccessToken(applicationContext,accountData.idToken) val intent = Intent() intent.putExtra("accessToken",accessToken as Serializable) setResult(RESULT_OK, intent) finish() } private fun refreshAccessToken(context:Context,idToken: String): AccessToken { // ========================================== // ========================================== // VVVVVV Breaks on this rest call VVVVVVVV val response = restCallToServer("get/accesstoken", "authtoken=${idToken}") // ^^^^^^ Breaks on this rest call ^^^^^^^^ // ========================================== // ========================================== // creates a serializable token used by rest of app from data provided by server val accessToken = AccessToken(response!!.getJSONObject("accessToken")) return accessToken; }
服务器代码(抛出上述异常)
const GOOGLE_OAUTH_CLIENT = new GoogleAuth.OAuth2Client(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET); async function VerifyIdToken(idToken,appName){ let credential,googuid; // vvvvv exception here vvvvv // vvvvv exception here vvvvv // vvvvv exception here vvvvv const ticket = await GOOGLE_OAUTH_CLIENT.verifyIdToken({ idToken, audience:GOOGLE_CLIENT_ID }); // ^^^^^ exception here ^^^^^ // ^^^^^ exception here ^^^^^ // ^^^^^ exception here ^^^^^ const credential = ticket.getPayload(); const googuid = credential.sub; const email = credential.email; // ... // access_token generated and tied to user account // ... // access_token sent back to client }
已尝试操作
- 无法测试物理设备连接开发服务器
- Device A上其他账号正常,Account A在其他设备上正常
- 物理机、虚拟机、调试包、发布包(除异常组合外)均正常
- Google自动化发布测试无问题
- 新版本/AAB无法解决问题
补充说明
- 该问题为新出现异常,触发原因未知
- 同一版本的其他渠道包无此问题
- 怀疑设备缓存证书或kid生成逻辑导致,但不确定
排查方向建议
- 捕获异常idToken并解析:在服务器端临时添加日志,捕获Account A在Device A发布包下生成的idToken,手动解析其header部分(对应异常中的kid),确认该kid是否存在于Google的公钥列表中。
- 强制刷新Google公钥缓存:google-auth-library会缓存公钥,可能服务器缓存的列表未包含该kid。可在初始化OAuth2Client时自定义缓存实现,或在异常时主动调用
GOOGLE_OAUTH_CLIENT.getIapPublicKeys()刷新缓存后重试验证。 - 检查设备端Google Play服务:Device A的Google Play服务版本过低或异常,可能导致生成的idToken使用了服务器未同步的密钥。引导用户更新或清除Google Play服务缓存后重试。
- 发布包签名校验:确认异常渠道的发布包签名与正常渠道是否一致,Google SignIn对签名校验严格,签名差异可能导致idToken异常。
- 账号特殊属性排查:检查Account A是否存在特殊设置(如双重验证、账号异常状态),结合Device A环境可能触发特殊逻辑。
内容的提问来源于stack exchange,提问作者cedar
相关产品推荐
相关产品推荐

