From 0eff982b0a58dcb9d16ffabcf584b065dafd84cf Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 16:58:52 +0000 Subject: [PATCH] feat: Implement UseUserAccessGroup for iOS This commit introduces the `UseUserAccessGroup` method in the Firebase C++ Authentication SDK. This method allows developers to specify a user access group for keychain operations on iOS, enabling keychain sharing between apps from the same developer. It wraps the `[FIRAuth useUserAccessGroup:error:]` Objective-C method. - Added `Auth::UseUserAccessGroup(const char* access_group)` to the public API in `firebase/auth.h`. - Implemented the method for iOS in `auth_ios.mm`, calling the corresponding FIRAuth method and handling potential errors. - Provided no-op stub implementations for Android and desktop platforms, as the functionality is iOS-specific. The method returns `kAuthErrorNone` on success or if it's a no-op on non-iOS platforms. On iOS, it returns an appropriate `AuthError` if the underlying Objective-C method reports an error. --- auth/src/android/auth_android.cc | 5 +++++ auth/src/desktop/auth_desktop.cc | 5 +++++ auth/src/include/firebase/auth.h | 22 ++++++++++++++++++++++ auth/src/ios/auth_ios.mm | 20 ++++++++++++++++++++ 4 files changed, 52 insertions(+) diff --git a/auth/src/android/auth_android.cc b/auth/src/android/auth_android.cc index e0a9a669cb..e72cc84156 100644 --- a/auth/src/android/auth_android.cc +++ b/auth/src/android/auth_android.cc @@ -670,6 +670,11 @@ void Auth::UseEmulator(std::string host, uint32_t port) { SetEmulatorJni(auth_data_, host.c_str(), port); } +AuthError Auth::UseUserAccessGroup(const char* access_group) { + // No-op on Android. + return kAuthErrorNone; +} + // Not implemented for Android. void EnableTokenAutoRefresh(AuthData* auth_data) {} void DisableTokenAutoRefresh(AuthData* auth_data) {} diff --git a/auth/src/desktop/auth_desktop.cc b/auth/src/desktop/auth_desktop.cc index dc9aca2950..5eb9d0e8dc 100644 --- a/auth/src/desktop/auth_desktop.cc +++ b/auth/src/desktop/auth_desktop.cc @@ -575,6 +575,11 @@ void Auth::UseEmulator(std::string host, uint32_t port) { auth_impl->assigned_emulator_url.append(std::to_string(port)); } +AuthError Auth::UseUserAccessGroup(const char* access_group) { + // No-op on desktop. + return kAuthErrorNone; +} + void InitializeTokenRefresher(AuthData* auth_data) { auto auth_impl = static_cast(auth_data->auth_impl); auth_impl->token_refresh_thread.Initialize(auth_data); diff --git a/auth/src/include/firebase/auth.h b/auth/src/include/firebase/auth.h index f6809c4a57..fddb2e1f53 100644 --- a/auth/src/include/firebase/auth.h +++ b/auth/src/include/firebase/auth.h @@ -173,6 +173,28 @@ class Auth { /// set_language_code(). void UseAppLanguage(); + /// @brief Uses the specified user access group for keychain operations on + /// iOS. + /// + /// This method should be called before any other Firebase Auth operations that + /// might interact with the keychain, such as sign-in or sign-out. + /// + /// On iOS, this method corresponds to `[FIRAuth useUserAccessGroup:]`. + /// If a value is provided, it will be used to set the user's access group, + /// which will be used to share credentials across apps from the same + /// developer. If `nullptr` is provided, it will clear any previously set + /// access group. + /// + /// On other platforms (Android, desktop), this method is a no-op and will + /// always return `kAuthErrorNone`. + /// + /// @param[in] access_group The access group to use, or `nullptr` to clear + /// the access group. + /// + /// @return `kAuthErrorNone` on success, or an `AuthError` code if an error + /// occurred on iOS (e.g., keychain error). + AuthError UseUserAccessGroup(const char* access_group); + // ----- Providers ------------------------------------------------------- /// Asynchronously requests the IDPs (identity providers) that can be used /// for the given email address. diff --git a/auth/src/ios/auth_ios.mm b/auth/src/ios/auth_ios.mm index a0292ba3b8..b168ada50a 100644 --- a/auth/src/ios/auth_ios.mm +++ b/auth/src/ios/auth_ios.mm @@ -590,6 +590,26 @@ void SignInCallback(FIRUser *_Nullable user, NSError *_Nullable error, SetEmulatorJni(auth_data_, host.c_str(), port); } +AuthError Auth::UseUserAccessGroup(const char* access_group) { + if (!auth_data_) { + return kAuthErrorNone; // Or appropriate error if auth_data_ is unexpectedly null + } + FIRAuth* fir_auth = AuthImpl(auth_data_); + NSString* ns_access_group = nil; + if (access_group) { + ns_access_group = [NSString stringWithUTF8String:access_group]; + } + + NSError* ns_error = nil; + BOOL success = [fir_auth useUserAccessGroup:ns_access_group error:&ns_error]; + + if (success) { + return kAuthErrorNone; + } else { + return AuthErrorFromNSError(ns_error); + } +} + // Remap iOS SDK errors reported by the UIDelegate. While these errors seem like // user interaction errors, they are actually caused by bad provider ids. NSError *RemapBadProviderIDErrors(NSError *_Nonnull error) {