From d8965fc4680c12362368d809840d2cda17141c83 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 18:01:38 +0000 Subject: [PATCH] feat(auth): Implement UseUserAccessGroup for C++ iOS SDK This commit implements the `UseUserAccessGroup` method in the Firebase C++ Auth SDK. This method is iOS-only and allows developers to specify a keychain access group for sharing authentication state across multiple apps from the same publisher. - Added the public API `UseUserAccessGroup(const char* access_group)` to `firebase::auth::Auth`. - Implemented the Objective-C wrapper in `auth_ios.mm` to call `[FIRAuth useUserAccessGroup:error:]`. - Added stub implementations for Android and Desktop platforms that log a warning and return `kAuthErrorNone`. - Included comprehensive Doxygen comments for the new API in `auth.h`. --- auth/src/android/auth_android.cc | 9 +++++++++ auth/src/desktop/auth_desktop.cc | 9 +++++++++ auth/src/include/firebase/auth.h | 32 ++++++++++++++++++++++++++++++++ auth/src/ios/auth_ios.mm | 20 ++++++++++++++++++++ 4 files changed, 70 insertions(+) diff --git a/auth/src/android/auth_android.cc b/auth/src/android/auth_android.cc index e0a9a669cb..49dbdc6cc6 100644 --- a/auth/src/android/auth_android.cc +++ b/auth/src/android/auth_android.cc @@ -670,6 +670,15 @@ void Auth::UseEmulator(std::string host, uint32_t port) { SetEmulatorJni(auth_data_, host.c_str(), port); } +AuthError Auth::UseUserAccessGroup(const char* access_group) { + // This is an iOS-only feature. No-op on Android. + (void)access_group; // Mark as unused + LogWarning( + "UseUserAccessGroup is an iOS-only feature and has no effect 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..d0e6c7af8f 100644 --- a/auth/src/desktop/auth_desktop.cc +++ b/auth/src/desktop/auth_desktop.cc @@ -575,6 +575,15 @@ 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) { + // This is an iOS-only feature. No-op on Desktop. + (void)access_group; // Mark as unused + LogWarning( + "UseUserAccessGroup is an iOS-only feature and has no effect 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..e076d81e27 100644 --- a/auth/src/include/firebase/auth.h +++ b/auth/src/include/firebase/auth.h @@ -428,6 +428,38 @@ class Auth { /// Get results of the most recent call to SendPasswordResetEmail. Future SendPasswordResetEmailLastResult() const; + /// @brief Sets the user access group to use for keychain data sharing. + /// + /// This method is only functional on iOS and tvOS. On other platforms, it is + /// a no-op and will return `kAuthErrorNone`. + /// + /// Allows you to specify a keychain access group to be used for sharing + /// authentication state across multiple apps from the same publisher. + /// Calling this method will switch the underlying data persistence for the + /// current Auth instance to the specified access group. + /// + /// If `access_group` is `nullptr` or an empty string, the access group will + /// be cleared and the default persistence (isolated to the app) will be + /// used. + /// + /// @param[in] access_group The keychain access group string (e.g., + /// "com.example.mygroup"). Pass `nullptr` or an empty string to reset to + /// the default app-specific keychain. + /// + /// @return `kAuthErrorNone` on success. + /// Returns `kAuthErrorKeychainError` if an error occurs while + /// accessing the keychain (iOS/tvOS only). + /// Returns `kAuthErrorUnimplemented` if called on a platform other + /// than iOS or tvOS, though current stub implementations return + /// `kAuthErrorNone`. + /// + /// @note On tvOS, if `shareAuthStateAcrossDevices` is set to `true`, + /// attempting to set an access group may have specific behaviors or + /// limitations as outlined in the Firebase iOS SDK documentation. Refer to + /// the official Firebase documentation for `[FIRAuth + /// useUserAccessGroup:error:]` for more details. + AuthError UseUserAccessGroup(const char* access_group); + #ifndef SWIG /// @brief Registers a listener to changes in the authentication state. /// diff --git a/auth/src/ios/auth_ios.mm b/auth/src/ios/auth_ios.mm index a0292ba3b8..bd7334d103 100644 --- a/auth/src/ios/auth_ios.mm +++ b/auth/src/ios/auth_ios.mm @@ -608,5 +608,25 @@ void DisableTokenAutoRefresh(AuthData *auth_data) {} void InitializeTokenRefresher(AuthData *auth_data) {} void DestroyTokenRefresher(AuthData *auth_data) {} +AuthError Auth::UseUserAccessGroup(const char *access_group) { + if (!auth_data_ || !AuthImpl(auth_data_)) { + return kAuthErrorUninitialized; + } + + NSString *ns_access_group = nil; + if (access_group && strlen(access_group) > 0) { + ns_access_group = [NSString stringWithUTF8String:access_group]; + } + + NSError *error = nil; + BOOL success = [AuthImpl(auth_data_) useUserAccessGroup:ns_access_group error:&error]; + + if (success) { + return kAuthErrorNone; + } else { + return AuthErrorFromNSError(error); + } +} + } // namespace auth } // namespace firebase