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

Android应用Firebase匿名账号关联Apple Sign In遇403错误求助

解决Apple Sign In关联Firebase Auth时的403 Forbidden错误

问题背景

我的Android应用支持Firebase Auth匿名登录,后续可在设置页关联邮箱/密码或Google账号。添加Apple Sign In功能时,已按官方要求配置重定向URL、服务ID及密钥,但点击Apple登录页的「继续」后出现403 Forbidden错误,登录页面能正常显示。

相关代码片段:

private val appleSignInLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
    if (result.resultCode == Activity.RESULT_OK) {
        result.data?.let { data ->
            val response = AuthorizationResponse.fromIntent(data)
            val idToken = response?.idToken.orEmpty()
            val credential = OAuthProvider.newCredentialBuilder("apple.com")
                .setIdTokenWithRawNonce(idToken, originalRawNonce)
                .build()
            lifecycleScope.launch {
                try {
                    firebaseAuth.currentUser?.linkWithCredential(credential)?.await()?.let { result ->
                        updateUser(result.user?.email.orEmpty())
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
        } ?: run {
            println("---> received no data")
        }
    }
}

private fun linkUserToApple() {
    viewModel.loading()
    try {
        val rawNonce = generateNonce()
        val hashedNonce = sha256(rawNonce)
        originalRawNonce = rawNonce
        // Build Apple auth URI
        val serviceConfig = AuthorizationServiceConfiguration(
            Uri.parse("https://appleid.apple.com/auth/authorize"),
            Uri.parse("https://appleid.apple.com/auth/token")
        )
        val authRequest = AuthorizationRequest.Builder(
            serviceConfig,
            "client-id",
            ResponseTypeValues.CODE,
            Uri.parse("redirect-url")
        ).setScopes(listOf("name", "email"))
            .setResponseMode("form_post")
            .setResponseType("code id_token")
            .setNonce(hashedNonce)
            .build()
        val authService = AuthorizationService(this@ActivitySignup)
        val authIntent = authService.getAuthorizationRequestIntent(authRequest)
        appleSignInLauncher.launch(authIntent) // Launching intent
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

排查及解决方案

针对403错误,按以下步骤逐一排查:

  1. 检查重定向URL的精确匹配
    Apple对重定向URL的校验非常严格,必须与Apple Developer后台配置的完全一致,包括大小写、末尾是否带斜杠等。确保代码中Uri.parse("redirect-url")的内容和Apple Developer中「服务ID」对应的重定向URI完全相同,同时Firebase Auth控制台中Apple登录配置的重定向URL也要一致。

  2. 修正授权请求的响应类型与模式冲突
    代码中同时设置了ResponseTypeValues.CODE和setResponseType("code id_token"),且指定了responseMode="form_post",这会导致请求参数冲突。对于Android应用的Apple Sign In,推荐使用responseMode="fragment",并且统一响应类型:

    val authRequest = AuthorizationRequest.Builder(
        serviceConfig,
        "你的Service ID",
        ResponseTypeValues.ID_TOKEN, // 直接用ID_TOKEN模式
        Uri.parse("你的重定向URL")
    ).setScopes(listOf("email"))
        .setResponseMode("fragment")
        .setNonce(hashedNonce)
        .build()
    

    不需要同时请求code和id_token,Firebase Auth只需要id_token即可完成凭证校验。

  3. 验证Nonce生成与哈希的正确性
    确保generateNonce()生成的是随机字符串(长度至少10位),sha256()函数正确实现了SHA-256哈希,且哈希后的nonce是Base64 URL编码格式(不带末尾的=,替换+为-,/为_)。如果哈希格式错误,Firebase会拒绝凭证,间接导致Apple返回403。

  4. 检查Firebase Auth的Apple配置
    登录Firebase控制台,确认Apple登录的配置中:

    • 服务ID(Service ID)与Apple Developer后台的一致
    • 上传的Apple私钥(.p8文件)正确,且密钥的ID与配置中的「密钥ID」匹配
    • 团队ID(Team ID)填写正确
  5. 确认应用签名与Apple配置匹配
    Apple Developer后台的服务ID需要关联应用的签名证书,确保你打包应用时使用的签名证书与Apple Developer中配置的一致(包括调试和发布版本)。如果是调试版本,需要把调试签名的SHA-1添加到Firebase控制台的应用配置中。

  6. 移除重复的响应类型设置
    代码中AuthorizationRequest.Builder的第三个参数已经指定了ResponseTypeValues.CODE,后面又调用setResponseType("code id_token"),这会覆盖之前的设置,导致请求参数混乱。只保留一种响应类型即可,推荐用ID_TOKEN模式简化流程。

修正后的核心代码示例

private fun linkUserToApple() {
    viewModel.loading()
    try {
        val rawNonce = generateNonce()
        val hashedNonce = sha256(rawNonce)
        originalRawNonce = rawNonce
        
        val serviceConfig = AuthorizationServiceConfiguration(
            Uri.parse("https://appleid.apple.com/auth/authorize"),
            Uri.parse("https://appleid.apple.com/auth/token")
        )
        
        val authRequest = AuthorizationRequest.Builder(
            serviceConfig,
            "your-service-id", // 替换为你的Apple Service ID
            ResponseTypeValues.ID_TOKEN,
            Uri.parse("your-redirect-url") // 替换为精确匹配的重定向URL
        ).setScopes(listOf("email"))
            .setResponseMode("fragment")
            .setNonce(hashedNonce)
            .build()
            
        val authService = AuthorizationService(this@ActivitySignup)
        val authIntent = authService.getAuthorizationRequestIntent(authRequest)
        appleSignInLauncher.launch(authIntent)
    } catch (e: Exception) {
        e.printStackTrace()
        viewModel.loadFailed("Apple登录初始化失败")
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 10:54:53