Android应用Firebase匿名账号关联Apple Sign In遇403错误求助
问题背景
我的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错误,按以下步骤逐一排查:
检查重定向URL的精确匹配
Apple对重定向URL的校验非常严格,必须与Apple Developer后台配置的完全一致,包括大小写、末尾是否带斜杠等。确保代码中Uri.parse("redirect-url")的内容和Apple Developer中「服务ID」对应的重定向URI完全相同,同时Firebase Auth控制台中Apple登录配置的重定向URL也要一致。修正授权请求的响应类型与模式冲突
代码中同时设置了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即可完成凭证校验。验证Nonce生成与哈希的正确性
确保generateNonce()生成的是随机字符串(长度至少10位),sha256()函数正确实现了SHA-256哈希,且哈希后的nonce是Base64 URL编码格式(不带末尾的=,替换+为-,/为_)。如果哈希格式错误,Firebase会拒绝凭证,间接导致Apple返回403。检查Firebase Auth的Apple配置
登录Firebase控制台,确认Apple登录的配置中:- 服务ID(Service ID)与Apple Developer后台的一致
- 上传的Apple私钥(.p8文件)正确,且密钥的ID与配置中的「密钥ID」匹配
- 团队ID(Team ID)填写正确
确认应用签名与Apple配置匹配
Apple Developer后台的服务ID需要关联应用的签名证书,确保你打包应用时使用的签名证书与Apple Developer中配置的一致(包括调试和发布版本)。如果是调试版本,需要把调试签名的SHA-1添加到Firebase控制台的应用配置中。移除重复的响应类型设置
代码中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

