You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过CredentialManager获取serverAuthCode以兼容后端?

如何通过CredentialManager获取Google登录的serverAuthCode以兼容后端?

我们正在升级应用,采用CredentialManager实现登录,但新方案中无法获取serverAuthCode。由于后端仅接收该参数而非idToken,必须获取它来保持兼容性。

旧实现代码(可正常获取serverAuthCode)

val task = GoogleSignIn.getSignedInAccountFromIntent(activityResult.data)
val account = try {
    task.getResult(ApiException::class.java)
} catch (e: ApiException) {
    // 异常处理
    null
}
val serverAuthCode = account?.serverAuthCode
// 调用后端接口

新CredentialManager实现(仅能获取idToken)

val googleIdOption = GetSignInWithGoogleOption.Builder("our serverClientId").build()
val request = GetCredentialRequest.Builder()
    .addCredentialOption(googleIdOption)
    .build()
val credentialManager = CredentialManager.create(context)
val response = credentialManager.getCredential(context, request)
val credential = response.credential
if (credential is CustomCredential && credential.type == TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
    try {
        val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credential.data)
        // 后续逻辑及接口调用
    } catch (e: Exception) {
        // 异常处理
    }
}

如上所示,新实现仅能获取idToken,无法获取serverAuthCode。我们尝试了授权处理代码,但serverAuthCode始终为null:

val authorizationLauncher = rememberAuthorizationLauncher()

val requestedScopes = listOf(
    Scope(Scopes.PLUS_ME),
    Scope(Scopes.PROFILE),
    Scope("https://www.googleapis.com/auth/user.birthday.read"),
    Scope("https://www.googleapis.com/auth/user.gender.read"),
    Scope("https://www.googleapis.com/auth/userinfo.email")
)

val authorizationRequest = AuthorizationRequest.builder().setRequestedScopes(requestedScopes).build()

Identity.getAuthorizationClient(context)
    .authorize(authorizationRequest)
    .addOnSuccessListener { authorizationResult ->
        if (authorizationResult.hasResolution()) {
            authorizationResult.pendingIntent?.intentSender?.let { intentSender ->
            authorizationLauncher.launch(IntentSenderRequest.Builder(intentSender).build())
            }
        } else {
            authorizationResult.serverAuthCode // 始终为null
        }
    }

@Composable
private fun rememberAuthorizationLauncher(
    activity: Activity = LocalActivity.current
) = rememberLauncherForActivityResult(
    contract = ActivityResultContracts.StartIntentSenderForResult()
) { activityResult ->
    if (activityResult.resultCode == Activity.RESULT_OK) {
        Identity.getAuthorizationClient(activity).getAuthorizationResultFromIntent(activityResult.data)
    }
}

解决方案

要获取有效的serverAuthCode,需要在授权请求中明确配置关键参数,并正确处理授权回调:

1. 修正AuthorizationRequest配置

必须指定后端的Web Client ID和响应类型为CODE,这是获取serverAuthCode的核心要求:

val authorizationLauncher = rememberAuthorizationLauncher()

// 保留必要的权限范围,移除已废弃的权限
val requestedScopes = listOf(
    Scope("https://www.googleapis.com/auth/userinfo.email"),
    Scope("https://www.googleapis.com/auth/userinfo.profile")
)

val authorizationRequest = AuthorizationRequest.builder()
    .setRequestedScopes(requestedScopes)
    // 替换为你的Google Cloud Console中Web客户端的Client ID
    .setServerClientId("your_web_server_client_id")
    // 指定响应类型为CODE,明确要求返回serverAuthCode
    .setResponseType(AuthorizationRequest.ResponseType.CODE)
    .build()

Identity.getAuthorizationClient(context)
    .authorize(authorizationRequest)
    .addOnSuccessListener { authorizationResult ->
        if (authorizationResult.hasResolution()) {
            authorizationResult.pendingIntent?.intentSender?.let { intentSender ->
                authorizationLauncher.launch(IntentSenderRequest.Builder(intentSender).build())
            }
        }
    }

2. 正确在回调中提取serverAuthCode

在授权完成后的回调中,从返回的Intent解析出结果并获取serverAuthCode:

@Composable
private fun rememberAuthorizationLauncher(
    activity: Activity = LocalActivity.current
) = rememberLauncherForActivityResult(
    contract = ActivityResultContracts.StartIntentSenderForResult()
) { activityResult ->
    if (activityResult.resultCode == Activity.RESULT_OK) {
        val authorizationResult = Identity.getAuthorizationClient(activity)
            .getAuthorizationResultFromIntent(activityResult.data)
        
        // 这里可以获取到有效的serverAuthCode
        authorizationResult.serverAuthCode?.let { serverAuthCode ->
            // 调用后端接口,传入serverAuthCode
        }
    }
}

关键注意事项

  • Server Client ID必须为Web客户端ID:在Google Cloud Console中,创建一个Web类型的OAuth客户端ID,而非Android客户端ID,将其填入setServerClientId。
  • 权限范围精简:移除已废弃的Scopes.PLUS_ME,保留必要的email和profile范围即可,多余权限可能导致授权流程异常。
  • OAuth同意屏幕配置:确保Google Cloud Console中的OAuth同意屏幕已配置正确的应用信息和权限范围,测试阶段可添加测试用户。

内容的提问来源于stack exchange,提问作者Pedro Almeida

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 08:36:01