/// <summary>
        /// Deletes an app's token from MacOS KeyChain.
        /// </summary>
        /// <param name="appId">An app/client id.</param>
        public static void DeleteToken(string appId)
        {
            if (string.IsNullOrEmpty(appId))
            {
                throw new ArgumentNullException(string.Format(
                                                    CultureInfo.CurrentCulture,
                                                    ErrorConstants.Message.NullOrEmptyParameter,
                                                    nameof(appId)));
            }

            IntPtr passwordDataPtr = IntPtr.Zero;
            IntPtr itemPtr         = IntPtr.Zero;

            try
            {
                int resultStatus = MacNativeKeyChain.SecKeychainFindGenericPassword(
                    keychainOrArray: IntPtr.Zero,
                    serviceNameLength: (uint)Constants.TokenCacheServiceName.Length,
                    serviceName: Constants.TokenCacheServiceName,
                    accountNameLength: (uint)appId.Length,
                    accountName: appId,
                    passwordLength: out uint passwordLength,
                    passwordData: out passwordDataPtr,
                    itemRef: out itemPtr);

                if (resultStatus == MacNativeKeyChain.SecResultCodes.errSecItemNotFound ||
                    itemPtr == IntPtr.Zero)
                {
                    return;
                }
                else if (resultStatus != MacNativeKeyChain.SecResultCodes.errSecSuccess)
                {
                    throw new Exception(string.Format(
                                            CultureInfo.CurrentCulture,
                                            ErrorConstants.Message.MacKeyChainFailed,
                                            "SecKeychainFindGenericPassword",
                                            resultStatus));
                }

                resultStatus = MacNativeKeyChain.SecKeychainItemDelete(itemPtr);
                if (resultStatus != MacNativeKeyChain.SecResultCodes.errSecSuccess)
                {
                    throw new Exception(string.Format(
                                            CultureInfo.CurrentCulture,
                                            ErrorConstants.Message.MacKeyChainFailed,
                                            "SecKeychainItemDelete",
                                            resultStatus));
                }
            }
            finally
            {
                FreePointers(ref itemPtr, ref passwordDataPtr);
            }
        }
        /// <summary>
        /// Frees up memory referenced by a keychain data and/or a CFType object after use.
        /// </summary>
        /// <param name="itemPtr">A pointer to a generic password item.</param>
        /// <param name="passwordDataPtr">A pointer to the data buffer to release.</param>
        private static void FreePointers(ref IntPtr itemPtr, ref IntPtr passwordDataPtr)
        {
            if (itemPtr != IntPtr.Zero)
            {
                MacNativeKeyChain.CFRelease(itemPtr);
                itemPtr = IntPtr.Zero;
            }

            if (passwordDataPtr != IntPtr.Zero)
            {
                MacNativeKeyChain.SecKeychainItemFreeContent(attrList: IntPtr.Zero, data: passwordDataPtr);
                passwordDataPtr = IntPtr.Zero;
            }
        }
        public static void Remove(string appId)
        {
            IntPtr passwordDataPtr = IntPtr.Zero;
            IntPtr itemPtr         = IntPtr.Zero;

            try
            {
                int resultStatus = MacNativeKeyChain.SecKeychainFindGenericPassword(
                    keychainOrArray: IntPtr.Zero,
                    serviceNameLength: (uint)ServiceName.Length,
                    serviceName: ServiceName,
                    accountNameLength: (uint)appId.Length,
                    accountName: appId,
                    passwordLength: out uint passwordLength,
                    passwordData: out passwordDataPtr,
                    itemRef: out itemPtr);

                if (resultStatus == MacNativeKeyChain.SecResultCodes.errSecItemNotFound)
                {
                    return;
                }
                else if (resultStatus != MacNativeKeyChain.SecResultCodes.errSecSuccess)
                {
                    throw new Exception($"SecKeychainFindGenericPassword failed with {resultStatus}");
                }

                if (itemPtr == IntPtr.Zero)
                {
                    return;
                }

                resultStatus = MacNativeKeyChain.SecKeychainItemDelete(itemPtr);
                if (resultStatus != MacNativeKeyChain.SecResultCodes.errSecSuccess)
                {
                    throw new Exception($"SecKeychainItemDelete failed with {resultStatus}");
                }
            }
            finally
            {
                FreePointers(ref itemPtr, ref passwordDataPtr);
            }
        }
        /// <summary>
        /// Adds or updates an app's token to MacOS KeyChain.
        /// </summary>
        /// <param name="appId">An app/client id.</param>
        /// <param name="plainContent">The content to store.</param>
        public static void SetToken(string appId, byte[] plainContent)
        {
            if (string.IsNullOrEmpty(appId))
            {
                throw new ArgumentNullException(string.Format(
                                                    CultureInfo.CurrentCulture,
                                                    ErrorConstants.Message.NullOrEmptyParameter,
                                                    nameof(appId)));
            }
            if (plainContent == null || plainContent.Length == 0)
            {
                return;
            }

            IntPtr passwordDataPtr = IntPtr.Zero;
            IntPtr itemPtr         = IntPtr.Zero;

            try
            {
                int resultStatus = MacNativeKeyChain.SecKeychainFindGenericPassword(
                    keychainOrArray: IntPtr.Zero,
                    serviceNameLength: (uint)Constants.TokenCacheServiceName.Length,
                    serviceName: Constants.TokenCacheServiceName,
                    accountNameLength: (uint)appId.Length,
                    accountName: appId,
                    passwordLength: out uint passwordLength,
                    passwordData: out passwordDataPtr,
                    itemRef: out itemPtr);

                switch (resultStatus)
                {
                case MacNativeKeyChain.SecResultCodes.errSecSuccess:
                    // Key exists, let's update it.
                    resultStatus = MacNativeKeyChain.SecKeychainItemModifyAttributesAndData(
                        itemRef: itemPtr,
                        attrList: IntPtr.Zero,
                        passwordLength: (uint)plainContent.Length,
                        passwordData: plainContent);

                    if (resultStatus != MacNativeKeyChain.SecResultCodes.errSecSuccess)
                    {
                        throw new Exception(string.Format(
                                                CultureInfo.CurrentCulture,
                                                ErrorConstants.Message.MacKeyChainFailed,
                                                "SecKeychainItemModifyAttributesAndData",
                                                resultStatus));
                    }
                    break;

                case MacNativeKeyChain.SecResultCodes.errSecItemNotFound:
                    // Key not found, let's create a new one in the default keychain.
                    resultStatus = MacNativeKeyChain.SecKeychainAddGenericPassword(
                        keychain: IntPtr.Zero,
                        serviceNameLength: (uint)Constants.TokenCacheServiceName.Length,
                        serviceName: Constants.TokenCacheServiceName,
                        accountNameLength: (uint)appId.Length,
                        accountName: appId,
                        passwordLength: (uint)plainContent.Length,
                        passwordData: plainContent,
                        itemRef: out itemPtr);

                    if (resultStatus != MacNativeKeyChain.SecResultCodes.errSecSuccess)
                    {
                        throw new Exception(string.Format(
                                                CultureInfo.CurrentCulture,
                                                ErrorConstants.Message.MacKeyChainFailed,
                                                "SecKeychainAddGenericPassword",
                                                resultStatus));
                    }
                    break;

                default:
                    throw new Exception(string.Format(
                                            CultureInfo.CurrentCulture,
                                            ErrorConstants.Message.MacKeyChainFailed,
                                            "SecKeychainFindGenericPassword",
                                            resultStatus));
                }
            }
            finally
            {
                FreePointers(ref itemPtr, ref passwordDataPtr);
            }
        }
        public static void AddOrUpdate(string appId, byte[] plainContent)
        {
            IntPtr passwordDataPtr = IntPtr.Zero;
            IntPtr itemPtr         = IntPtr.Zero;

            try
            {
                int resultStatus = MacNativeKeyChain.SecKeychainFindGenericPassword(
                    keychainOrArray: IntPtr.Zero,
                    serviceNameLength: (uint)ServiceName.Length,
                    serviceName: ServiceName,
                    accountNameLength: (uint)appId.Length,
                    accountName: appId,
                    passwordLength: out uint passwordLength,
                    passwordData: out passwordDataPtr,
                    itemRef: out itemPtr);

                if (resultStatus != MacNativeKeyChain.SecResultCodes.errSecSuccess &&
                    resultStatus != MacNativeKeyChain.SecResultCodes.errSecItemNotFound)
                {
                    throw new Exception($"SecKeychainFindGenericPassword failed with {resultStatus}");
                }

                if (itemPtr != IntPtr.Zero)
                {
                    // Key exists, let's update it.
                    resultStatus = MacNativeKeyChain.SecKeychainItemModifyAttributesAndData(
                        itemRef: itemPtr,
                        attrList: IntPtr.Zero,
                        passwordLength: (uint)plainContent.Length,
                        passwordData: plainContent);

                    if (resultStatus != MacNativeKeyChain.SecResultCodes.errSecSuccess)
                    {
                        throw new Exception($"SecKeychainItemModifyAttributesAndData failed with {resultStatus}");
                    }
                }
                else
                {
                    // Key not found, let's create a new one in the default keychain.
                    resultStatus = MacNativeKeyChain.SecKeychainAddGenericPassword(
                        keychain: IntPtr.Zero,
                        serviceNameLength: (uint)ServiceName.Length,
                        serviceName: ServiceName,
                        accountNameLength: (uint)appId.Length,
                        accountName: appId,
                        passwordLength: (uint)plainContent.Length,
                        passwordData: plainContent,
                        itemRef: out itemPtr);

                    if (resultStatus != MacNativeKeyChain.SecResultCodes.errSecSuccess)
                    {
                        throw new Exception($"SecKeychainAddGenericPassword failed with {resultStatus}");
                    }
                }
            }
            finally
            {
                FreePointers(ref itemPtr, ref passwordDataPtr);
            }
        }