diff --git a/auth/integration_test/src/integration_test.cc b/auth/integration_test/src/integration_test.cc index eef1301adc..6bd8d47a43 100644 --- a/auth/integration_test/src/integration_test.cc +++ b/auth/integration_test/src/integration_test.cc @@ -1513,4 +1513,18 @@ TEST_F(FirebaseAuthTest, TestLinkFederatedProviderBadProviderIdFails) { #endif // defined(ENABLE_OAUTH_TESTS) +#if TARGET_OS_IPHONE +TEST_F(FirebaseAuthTest, TestUseUserAccessGroup) { + // This is a simple smoke test to ensure the method can be called + // without crashing on iOS. + // Deeper testing of keychain access group functionality would require + // more complex setup and is typically done manually or with UI tests. + // We don't check the return value as keychain sharing may not be configured, + // leading to legitimate errors. + auth_->UseUserAccessGroup(nullptr); + auth_->UseUserAccessGroup("test-group"); + auth_->UseUserAccessGroup(""); +} +#endif // TARGET_OS_IPHONE + } // namespace firebase_testapp_automated diff --git a/auth/src/android/auth_android.cc b/auth/src/android/auth_android.cc index e0a9a669cb..335a9e5173 100644 --- a/auth/src/android/auth_android.cc +++ b/auth/src/android/auth_android.cc @@ -676,5 +676,10 @@ void DisableTokenAutoRefresh(AuthData* auth_data) {} void InitializeTokenRefresher(AuthData* auth_data) {} void DestroyTokenRefresher(AuthData* auth_data) {} +AuthError Auth::UseUserAccessGroup(const char* access_group) { + // This is an iOS-only feature. No-op on other platforms. + return kAuthErrorNone; +} + } // namespace auth } // namespace firebase diff --git a/auth/src/desktop/auth_desktop.cc b/auth/src/desktop/auth_desktop.cc index dc9aca2950..e934013c64 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) { + // This is an iOS-only feature. No-op on other platforms. + 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..93f5b023d4 100644 --- a/auth/src/include/firebase/auth.h +++ b/auth/src/include/firebase/auth.h @@ -517,6 +517,19 @@ class Auth { /// not available on the current device. static Auth* GetAuth(App* app, InitResult* init_result_out = nullptr); + /// @brief Specifies a user access group for iCloud keychain access. + /// + /// This method is only functional on iOS. On other platforms, it is a no-op + /// and will always return `kAuthErrorNone`. + /// + /// @param[in] access_group The user access group to use. Set to `nullptr` + /// to use the default access group. An empty string will be passed as an + /// empty string. + /// + /// @return `kAuthErrorNone` on success, or an AuthError code if an error + /// occurred. + AuthError UseUserAccessGroup(const char* access_group); + private: /// @cond FIREBASE_APP_INTERNAL friend class ::firebase::App; diff --git a/auth/src/ios/auth_ios.mm b/auth/src/ios/auth_ios.mm index a0292ba3b8..785b8e4c45 100644 --- a/auth/src/ios/auth_ios.mm +++ b/auth/src/ios/auth_ios.mm @@ -608,5 +608,23 @@ void DisableTokenAutoRefresh(AuthData *auth_data) {} void InitializeTokenRefresher(AuthData *auth_data) {} void DestroyTokenRefresher(AuthData *auth_data) {} +AuthError Auth::UseUserAccessGroup(const char* access_group_str) { + if (!auth_data_) { + return kAuthErrorFailure; + } + NSString* access_group_ns_str = nil; + if (access_group_str != nullptr) { + access_group_ns_str = [NSString stringWithUTF8String:access_group_str]; + } + + NSError* error = nil; + BOOL success = [AuthImpl(auth_data_) useUserAccessGroup:access_group_ns_str error:&error]; + if (success) { + return kAuthErrorNone; + } else { + return AuthErrorFromNSError(error); + } +} + } // namespace auth } // namespace firebase