[Bug] iOS: OAuthProvider::GetCredential with raw_nonce and null access_token sends empty access_token, Sign in with Apple fails with "Invalid OAuth response from apple.com"

未關閉 適合新手
#1,954 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

維護者通常 2 天內回覆

還沒有人認領這個 Issue。

評估

難度
2/5
預估耗時
1-3 小時
新手友好度
82/100
Issue 類型
缺陷
描述清晰度
描述清楚
活躍度
活躍
技術堆疊
cpp, ios, objective-c

研究方向

從 auth/src/ios/credential_ios.mm 開始,並比較 issue 中描述的 iOS 憑證選擇器。檢查 4 參數的 GetCredential 呼叫如何處理 null access_token。完成標準是:在這種情況下使用不帶 access_token 的選擇器,讓請求不包含空的 access_token,並且 Apple 登入能夠成功。

由索引模型根據 Issue 內容生成。

描述

[REQUIRED] Please fill in the following fields:
  • Pre-built SDK from the website or open-source from this repo: Pre-built SDK from the website (firebase_cpp_sdk_13.13.0.zip)
  • Firebase C++ SDK version: 13.13.0. The same code is in 13.13.1, 14.0.0, 14.1.0 and main.
  • Problematic Firebase Component: Auth
  • Other Firebase Components in use: App, Firestore, Functions, Analytics, Crashlytics, Remote Config, Storage, Database
  • Platform you are using the C++ SDK on: Mac
  • Platform you are targeting: iOS (Firebase iOS SDK 12.19.1, iPhone 13)
[REQUIRED] Please describe the issue here:

On iOS, Sign in with Apple always fails when the credential comes from OAuthProvider::GetCredential(provider_id, id_token, raw_nonce, access_token) with access_token == nullptr, as the Apple C++ guide recommends. Both Auth::SignInAndRetrieveDataWithCredential and User::LinkWithCredential return:

error 4 (kAuthErrorInvalidCredential): "Invalid OAuth response from apple.com"

The backend reply is INVALID_IDP_RESPONSE : Invalid OAuth response from apple.com.

Root cause

auth/src/ios/credential_ios.mm passes nil when access_token is null:

NSString* access_token_string =
    (access_token != nullptr) ? util::CStringToNSString(access_token) : nullptr;
FIRAuthCredential* credential =
    (FIRAuthCredential*)[FIROAuthProvider credentialWithProviderID:@(provider_id)
                                                           IDToken:@(id_token)
                                                          rawNonce:@(raw_nonce)
                                                       accessToken:access_token_string];

Since the Swift rewrite of FirebaseAuth (iOS SDK 11+), this selector's accessToken is a non-optional String. See FirebaseAuth/Sources/Swift/AuthProvider/OAuthProvider.swift:

@objc(credentialWithProviderID:IDToken:rawNonce:accessToken:)
public static func credential(withProviderID providerID: String, idToken: String,
                              rawNonce: String,
                              accessToken: String) -> OAuthCredential

Passing nil from Objective-C into a non-optional Swift String bridges to an empty string. OAuthCredential then sets providerAccessToken = "", and the verifyAssertion / signInWithIdp post body includes access_token=. The backend tries to validate the empty access token against apple.com and rejects the request.

The iOS SDK already has a selector for this case: credentialWithProviderID:IDToken:rawNonce:, which takes no access token. Apple also has its own factory: appleCredentialWithIDToken:rawNonce:fullName:.

Evidence

We logged the Apple identity token and raw nonce on the device, then sent them straight to accounts:signInWithIdp over REST:

postBody Result
id_token=…&providerId=apple.com&nonce=<raw> 200 OK (sign-in and link both work)
id_token=…&access_token=&providerId=apple.com&nonce=<raw> 400 INVALID_IDP_RESPONSE : Invalid OAuth response from apple.com, the same error the C++ SDK returns
id_token=…&providerId=apple.com 400 MISSING_OR_INVALID_NONCE : Nonce is missing in the request.

The token is valid: iss = https://appleid.apple.com, aud = <bundle id>, and nonce equals the SHA-256 of the raw nonce. The project is configured correctly, because the same token succeeds without access_token=.

Suggested fix

In auth/src/ios/credential_ios.mm, use the no-access-token selector when access_token is null:

Credential OAuthProvider::GetCredential(const char* provider_id, const char* id_token,
                                        const char* raw_nonce, const char* access_token) {
  FIREBASE_ASSERT_RETURN(Credential(), provider_id && id_token && raw_nonce);
  FIRAuthCredential* credential =
      access_token != nullptr
          ? (FIRAuthCredential*)[FIROAuthProvider credentialWithProviderID:@(provider_id)
                                                                   IDToken:@(id_token)
                                                                  rawNonce:@(raw_nonce)
                                                               accessToken:@(access_token)]
          : (FIRAuthCredential*)[FIROAuthProvider credentialWithProviderID:@(provider_id)
                                                                   IDToken:@(id_token)
                                                                  rawNonce:@(raw_nonce)];
  return Credential(new FIRAuthCredentialPointer(credential));
}

This only affects the 4-argument overload. The 3-argument GetCredential(provider_id, id_token, access_token) asserts that access_token is non-null, so it never passes nil.

Steps to reproduce:

Have you been able to reproduce this issue with just the Firebase C++ quickstarts ?
Not tried with the quickstart. We reproduced it in our own app and with the minimal code below.

What's the issue repro rate? (eg 100%, 1/5 etc)
100% on a real device.

What happened? How can we make the problem occur?

  1. Enable the Apple provider in the Firebase console. Add the com.apple.developer.applesignin entitlement to the iOS app.
  2. Run ASAuthorizationAppleIDProvider with request.nonce = SHA256(rawNonce).
  3. Take identityToken from the returned ASAuthorizationAppleIDCredential.
  4. Call OAuthProvider::GetCredential("apple.com", idToken, rawNonce, nullptr), then SignInAndRetrieveDataWithCredential or LinkWithCredential.
  5. The future completes with error 4, "Invalid OAuth response from apple.com". No apple.com user is created.
Relevant Code:
// Objective-C++ on iOS, after ASAuthorizationController succeeds
ASAuthorizationAppleIDCredential *apple = (ASAuthorizationAppleIDCredential *)authorization.credential;
NSString *idToken = [[NSString alloc] initWithData:apple.identityToken encoding:NSUTF8StringEncoding];

firebase::auth::Credential credential = firebase::auth::OAuthProvider::GetCredential(
    "apple.com", idToken.UTF8String, rawNonce.UTF8String, /*access_token=*/nullptr);

// Either call fails with kAuthErrorInvalidCredential: "Invalid OAuth response from apple.com"
auth->SignInAndRetrieveDataWithCredential(credential);
auth->current_user().LinkWithCredential(credential);
主要語言
C++
星號
325
分支
137
平均合併
2 天 20 小時
30 天內合併 PR
15

環境準備

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

firebase/firebase-cpp-sdk 的其他 Issue

查看 firebase/firebase-cpp-sdk 的全部 Issue

相似的 Issue

更多 C++ Issue

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。