diff --git a/docs/PowerAuth-SDK-for-Android.md b/docs/PowerAuth-SDK-for-Android.md index 2394e37f..a46c2d1e 100644 --- a/docs/PowerAuth-SDK-for-Android.md +++ b/docs/PowerAuth-SDK-for-Android.md @@ -144,7 +144,7 @@ PowerAuthAppLifecycleListener.getInstance().registerForActivityLifecycleCallback ``` -### Additional configuration methods +### Additional configuration The `PowerAuthConfiguration.Builder` class provides the following additional methods that can alter the configuration: @@ -152,6 +152,34 @@ The `PowerAuthConfiguration.Builder` class provides the following additional met - `externalEncryptionKey()` - See [External Encryption Key](#external-encryption-key) chapter for more details. - `disableAutomaticProtocolUpgrade()` - Disables the automatic protocol upgrade. This option should be used only for debugging purposes. +### HTTP client configuration + +The `PowerAuthClientConfiguration.Builder` class contains configuration for a HTTP client used internally by `PowerAuthSDK` class. It has the following configuration properties: + +- `timeouts()` - Function specifies connection and read timeout in milliseconds. +- `allowUnsecuredConnection()` - Enables or disables connection to unsecured servers. Do not use this option in the production build of your application. +- `clientValidationStrategy()` - Specifies TLS client validation strategy. See [Working with Invalid SSL Certificates](#working-with-invalid-ssl-certificates) for more details. +- `requestInterceptor()` - Adds a [request interceptor](#request-interceptors) used by the client before the request is executed. +- `userAgent()` - Specifies value for User-Agent HTTP request header. See [Custom User-Agent](#custom-user-agent) chapter for more details. + +### Keychain configuration + +The `PowerAuthKeychainConfiguration.Builder` class contains configuration for a keychain-based storage used by `PowerAuthSDK` class internally. The configuration contains the following properties: + +- `linkBiometricItemsToCurrentSet()` - Function specifies whether the item protected with the biometry is invalidated if fingers are added or removed, or if the user re-enrolls for face. See [Biometry Factor-Related Key Lifetime](#biometry-factor-related-key-lifetime) chapter for more details. +- `confirmBiometricAuthentication()` - Function specifies whether the user's confirmation will be required after the successful biometric authentication. See [Biometric Authentication Confirmation](#biometric-authentication-confirmation) chapter for more details. +- `authenticateOnBiometricKeySetup()` - Function specifies whether biometric key setup always require a biometric authentication. See [Enable Biometric Authentication](#enable-biometric-authentication) chapter for more details. +- `enableFallbackToSharedBiometryKey()` - Function specifies whether `PowerAuthSDK` instance should also do additional lookup for a legacy biometric key, previously shared between multiple PowerAuthSDK object instances. The default value is `true` and the fallback is enabled. If your application is using multiple `PowerAuthSDK` instances, then it's recommended to set this option to `false` to avoid use of the shared key between such instances. +- `minimalRequiredKeychainProtection()` - Function specifies minimal required keychain protection level that must be supported on the current device. See [Activation Data Protection](#activation-data-protection) chapter for more details. + +The following properties are also available for configuration but are not recommended to be altered under typical circumstances, as changing them may impact the library’s stability or intended behavior: + +- `keychainStatusId()` - Function specifies name of the Keychain file used for storing the status information. +- `keychainBiometryId()` - Function specifies name of the Keychain file used for storing the biometry key information. +- `keychainTokenStoreId()` - Function specifies name of the Keychain file used for storing the access tokens. +- `keychainKeyBiometry()` - Function specifies name of the key to the biometry Keychain to store biometry-factor protection key. + + ### Activation Data Protection By default, the PowerAuth Mobile SDK for Android encrypts the local activation data with a symmetric key generated by the Android KeyStore on Android 6 and newer devices. On older devices, or if the device has an unreliable KeyStore implementation, then the fallback to unencrypted storage, based on private [SharedPreferences](https://developer.android.com/reference/android/content/SharedPreferences) is used. If your application requires a higher level of activation data protection, then you can enforce the level of protection in `PowerAuthKeychainConfiguration`: @@ -853,36 +881,25 @@ fun validateTypedCharacters(input: String): String? { To obtain detailed activation status information, use the following code: - ```kotlin // Check if there is some activation on the device if (powerAuthSDK.hasValidActivation()) { // If there is an activation on the device, check the status with server powerAuthSDK.fetchActivationStatusWithCallback(context, object: IActivationStatusListener { override fun onActivationStatusSucceed(status: ActivationStatus) { - // Activation state: State_Created, State_Pending_Commit, State_Active, State_Blocked, State_Removed, State_Deadlock + // Activation states are explained in detail in "Activation states" chapter below when (status.state) { ActivationStatus.State_Pending_Commit -> - // Activation is awaiting commit on the server. Log.i(TAG, "Waiting for commit") ActivationStatus.State_Active -> - // Activation is valid and active. Log.i(TAG, "Activation is active") ActivationStatus.State_Blocked -> - // Activation is blocked. You can display unblock - // instructions to the user. Log.i(TAG, "Activation is blocked") ActivationStatus.State_Removed -> { - // Activation is no longer valid on the server. - // You can inform user about this situation and remove - // activation locally. Log.i(TAG, "Activation is no longer valid") powerAuthSDK.removeActivationLocal(context) } ActivationStatus.State_Deadlock -> { - // Local activation is technically blocked and no longer - // can be used for the signature calculations. You can inform - // user about this situation and remove activation locally. Log.i(TAG, "Activation is technically blocked") powerAuthSDK.removeActivationLocal(context) } @@ -907,75 +924,44 @@ if (powerAuthSDK.hasValidActivation()) { // No activation present on device } ``` -```java -// Check if there is some activation on the device -if (powerAuthSDK.hasValidActivation()) { - // If there is an activation on the device, check the status with server - powerAuthSDK.fetchActivationStatusWithCallback(context, new IActivationStatusListener() { - @Override - public void onActivationStatusSucceed(ActivationStatus status) { - // Activation state: State_Created, State_Pending_Commit, State_Active, State_Blocked, State_Removed, State_Deadlock - switch (status.state) { - case ActivationStatus.State_Pending_Commit: - // Activation is awaiting commit on the server. - android.util.Log.i(TAG, "Waiting for commit"); - break; - case ActivationStatus.State_Active: - // Activation is valid and active. - android.util.Log.i(TAG, "Activation is active"); - break; - case ActivationStatus.State_Blocked: - // Activation is blocked. You can display unblock - // instructions to the user. - android.util.Log.i(TAG, "Activation is blocked"); - break; - case ActivationStatus.State_Removed: - // Activation is no longer valid on the server. - // You can inform user about this situation and remove - // activation locally. - android.util.Log.i(TAG, "Activation is no longer valid"); - powerAuthSDK.removeActivationLocal(context); - break; - case ActivationStatus.State_Deadlock: - // Local activation is technically blocked and no longer - // can be used for the signature calculations. You can inform - // user about this situation and remove activation locally. - android.util.Log.i(TAG, "Activation is technically blocked"); - powerAuthSDK.removeActivationLocal(context); - break; - case ActivationStatus.State_Created: - // Activation is just created. This is the internal - // state on the server and therefore can be ignored - // on the mobile application. - default: - android.util.Log.i(TAG, "Unknown state"); - break; - } - // Failed login attempts, remaining = max - current - int currentFailCount = status.failCount; - int maxAllowedFailCount = status.maxFailCount; - int remainingFailCount = status.getRemainingAttempts(); +Note that the status fetch may fail at an unrecoverable error `PowerAuthErrorCodes.PROTOCOL_UPGRADE`, meaning that it's not possible to upgrade the PowerAuth protocol to a newer version. In this case, it's recommended to [remove the activation locally](#activation-removal). - if (status.getCustomObject() != null) { - // Custom object contains any proprietary server specific data - } - } +### Activation states - @Override - public void onActivationStatusFailed(Throwable t) { - // Network error occurred, report it to the user - } - }); -} else { - // No activation present on device -} -``` - +This chapter explains activation states in detail. To get more information about activation lifecycle, check the [Activation States](https://github.com/wultra/powerauth-crypto/blob/develop/docs/Activation.md#activation-states) chapter available in our [powerauth-crypto](https://github.com/wultra/powerauth-crypto) repository. -Note that the status fetch may fail at an unrecoverable error `PowerAuthErrorCodes.PROTOCOL_UPGRADE`, meaning that it's not possible to upgrade the PowerAuth protocol to a newer version. In this case, it's recommended to [remove the activation locally](#activation-removal). +#### `ActivationStatus.State_Created` + +The activation record is created using an external channel, such as the Internet banking, but the key exchange between the client and server did not happen yet. This state is never reported to the mobile client. + +#### `ActivationStatus.State_Pending_Commit` + +The activation record is created, and the key exchange between the client and server has already taken place, but the activation record on the server requires additional approval before it can be used. This approval is typically performed through an internet banking platform by the client or handled by an authorized representative in a back office system. + +#### `ActivationStatus.State_Active` + +The activation record is created and active. It is ready to be used for typical use-cases, such as generating signatures. + +#### `ActivationStatus.State_Blocked` + +The activation record is blocked and cannot be used for most use-cases, such as generating signatures. While it can be unblocked and activated again, the unblock process cannot be performed locally on the mobile device and requires intervention through an external system, such as internet banking or a back office platform. + +#### `ActivationStatus.State_Removed` + +The activation record is removed and permanently blocked. It cannot be used for generating signatures or ever unblocked. You can inform user about this situation and remove the activation locally. + +#### `ActivationStatus.State_Deadlock` + +The local activation is technically blocked and can no longer be used for signature calculations. You can inform the user about this situation and remove the activation locally. + +The reason why the mobile client is no longer capable of calculating valid signatures is that the logical counter is out of sync between the client and the server. This may happen only if the mobile client calculates too many PowerAuth signatures without subsequent validation on the server. For example: + +- If your application repeatedly constructs HTTP requests with a PowerAuth signature while the network is unreachable. +- If your application repeatedly creates authentication tokens while the network is unreachable. For example, when trying to register for push notifications in the background, without user interaction. +- If you calculate too many offline signatures without subsequent validation. -To get more information about activation lifecycle, check the [Activation States](https://github.com/wultra/powerauth-crypto/blob/develop/docs/Activation.md#activation-states) chapter available in our [powerauth-crypto](https://github.com/wultra/powerauth-crypto) repository. +In rare situations, this may also happen in development or testing environments, where you’re able to restore the state of the activation on the server from a snapshot. ## Data Signing diff --git a/docs/PowerAuth-SDK-for-iOS-Extensions.md b/docs/PowerAuth-SDK-for-iOS-Extensions.md index b0c97e4b..4c497b76 100644 --- a/docs/PowerAuth-SDK-for-iOS-Extensions.md +++ b/docs/PowerAuth-SDK-for-iOS-Extensions.md @@ -3,6 +3,7 @@ ## Table of Contents +- [Introduction](#introduction) - [Installation](#installation) - [CocoaPods Installation](#cocoapods) - [Manual Installation](#manual) @@ -24,6 +25,15 @@ Related documents: - [PowerAuth SDK for watchOS](./PowerAuth-SDK-for-watchOS.md) +## Introduction + +The PowerAuth Mobile SDK Extensions library is a lightweight counterpart to the full-featured PowerAuth Mobile SDK, providing limited functionality, such as: + +- Retrieving information about activation presence +- Obtaining authentication tokens + +If you need to perform more operations in your extension, such as calculating [PowerAuth symmetric signatures](./PowerAuth-SDK-for-iOS.md#symmetric-multi-factor-signature), you can use the full-featured [PowerAuth mobile SDK](./PowerAuth-SDK-for-iOS.md). This can be achieved by configuring [activation data sharing](./PowerAuth-SDK-for-iOS.md#share-activation-data) in both your application and the extension. + ## Installation This chapter describes how to get PowerAuth SDK for iOS and tvOS Extensions up and running in your app. In the current version, you can choose between CocoaPods and manual library integration. Both types of installation will lead to your app extension linked with a dynamic library, provided by the `PowerAuth2ForExtensions.[xc]framework`. @@ -146,13 +156,10 @@ class TodayViewController: UIViewController, NCWidgetProviding { }() private static func setupPowerAuth() -> PowerAuthExtensionSDK { - let config = PowerAuthConfiguration() - config.instanceId = "your-app-bundle-name"; - config.appKey = "sbG8gd...MTIzNA==" - config.appSecret = "aGVsbG...MTIzNA==" - config.masterServerPublicKey = "MTIzNDU2Nz...jc4OTAxMg==" - // URL is optional, the current version of Extensions SDK doesn't perform its own networking. - config.baseEndpointUrl = "https://localhost:8080/demo-server" + let config = PowerAuthConfiguration( + instanceId: Bundle.main.bundleIdentifier!, + baseEndpointUrl: "https://localhost:8080/demo-server", + configuration: "ARDDj6EB6iAUtNm...KKEcBxbnH9bMk8Ju3K1wmjbA==") let keychainConfig = PowerAuthKeychainConfiguration.sharedInstance() keychainConfig.keychainAttribute_AccessGroup = "KEYCHAIN_GROUP_IDENTIFIER" diff --git a/docs/PowerAuth-SDK-for-iOS.md b/docs/PowerAuth-SDK-for-iOS.md index 5d6a9c27..1009c93c 100644 --- a/docs/PowerAuth-SDK-for-iOS.md +++ b/docs/PowerAuth-SDK-for-iOS.md @@ -174,12 +174,42 @@ func application(_ application: UIApplication, didFinishLaunchingWithOptions lau } ``` -### Additional configuration properties +### Additional configuration + +The `PowerAuthConfiguration` has the following additional properties: - `offlineSignatureComponentLength` - Alters the default component length for the [offline signature](#symmetric-offline-multi-factor-signature). The values between 4 and 8 are allowed. The default value is 8. - `externalEncryptionKey` - See [External Encryption Key](#external-encryption-key) chapter for more details. -- `keychainKey_Biometry` - Specifies the 'key' used to store this PowerAuthSDK instance biometry-related key in the biometry key keychain. If not set, then `instanceId` is applied. -- `disableAutomaticProtocolUpgrade` - If set to `true`, then automatic protocol upgrade is disabled. This option should be used only for debugging purposes. +- `disableAutomaticProtocolUpgrade` - If set to `true`, then automatic protocol upgrade is disabled. This option should be used only for the debugging purposes. +- `keychainKey_Biometry` - Specifies the 'key' used to store the `PowerAuthSDK` instance’s biometry-related key in the biometry keychain. If not set, the `instanceId` is applied. Do not alter this configuration unless you have a valid reason to do so. + +### HTTP client configuration + +The `PowerAuthClientConfiguration` object contains configuration for a HTTP client used internally by `PowerAuthSDK` object. It has the following configuration properties: + +- `defaultRequestTimeout` - Property that specifies the default HTTP client request timeout. The default value is 20.0 seconds. +- `sslValidationStrategy` - Property that specifies the SSL validation strategy applied by the client. The default value is the default `URLSession` behavior. See [Working with Invalid SSL Certificates](#working-with-invalid-ssl-certificates) chapter for more details. +- `requestInterceptors`- Property that specifies the list of [request interceptors](#request-interceptors) used by the client before the request is executed. The default value is `nil`. +- `userAgent` - Property that specifies the content of User-Agent request header. The default is value calculated in `PowerAuthSystem.defaultUserAgent()` function. If you set `nil` to this property, then the default value provided by operating system is used. + +### Keychain configuration + +The `PowerAuthKeychainConfiguration` object contains configuration for a keychain-based storage used by `PowerAuthSDK` class internally. The configuration contains the following properties: + +- `keychainAttribute_AccessGroup` - Property that specifies a keychain access group in case that keychain is shared between multiple applications or between application and its extensions. +- `keychainAttribute_UserDefaultsSuiteName` - Property that specifies the name of `UserDefaults` suite to store the flag indicating that application has been re-installed. If the value is not provided, then `UserDefaults.standardUserDefaults` suite is used. +- `linkBiometricItemsToCurrentSet` - If set, then the item protected with the biometry is invalidated if fingers are added or removed for Touch ID, or if the user re-enrolls for Face ID. The default value is `false` (e.g. changing biometry in the system doesn't invalidate the entry) +- `allowBiometricAuthenticationFallbackToDevicePasscode` - If set to `true`, then the item protected with the biometry can be accessed also with a device passcode. If set, then `linkBiometricItemsToCurrentSet` option has no effect. The default is `false`, so fallback to device's passcode is not enabled. +- `invalidateLocalAuthenticationContextAfterUse` - If set to `true`, then the `LAContext` object provided by application is invalidated after the use in SDK. The default value is `true`, so `LAContext` cannot be reused for getting keys protected with biometry. + +The following properties are also available for configuration but are not recommended to be altered under typical circumstances, as changing them may impact the library’s stability or intended behavior: + +- `keychainInstanceName_Status` - Property that specifies the name of the Keychain service used to store statuses for different PowerAuth instances. You should not change this property unless you have a valid reason to do so. +- `keychainInstanceName_Possession` - Property that specifies the name of the Keychain service used to store possession factor related key (one value for all `PowerAuthSDK` instances). +- `keychainInstanceName_Biometry` - Property that specifies the name of the Keychain service used to store biometry related keys for different `PowerAuthSDK` instances. +- `keychainInstanceName_TokenStore` - Property that specifies the name of the Keychain service used to store content of `PowerAuthToken` objects. +- `keychainKey_Possession` - Property that specifies a storage key used to store possession fator related key in an associated possession Keychain service. + ## Activation @@ -192,7 +222,7 @@ The original activation method uses a one-time activation code generated in Powe Use the following code to create an activation once you have an activation code: ```swift -let deviceName = "Petr's iPhone 7" // or UIDevice.current.name +let deviceName = "Petr's iPhone 7" // or UIDevice.current.name (see warning below) let activationCode = "VVVVV-VVVVV-VVVVV-VTFVA" // let user type or QR-scan this value // Create an activation object with the given activation code. @@ -214,12 +244,16 @@ powerAuthSDK.createActivation(activation) { (result, error) in If the received activation result also contains recovery data, then you should display those values to the user. To do that, please read the [Getting Recovery Data](#getting-recovery-data) section of this document, which describes how to treat that sensitive information. This is relevant for all types of activation you use. + +Note that if you use `UIDevice.current.name` for a device’s name, your application must include an [appropriate entitlement](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_device-information_user-assigned-device-name); otherwise, the operating system will provide a generic `iPhone` string. + + #### Additional Activation OTP If an [additional activation OTP](https://github.com/wultra/powerauth-crypto/blob/develop/docs/Additional-Activation-OTP.md) is required to complete the activation, then use the following code to configure the `PowerAuthActivation` object: ```swift -let deviceName = "Petr's iPhone 7" // or UIDevice.current.name +let deviceName = "Petr's iPhone 7" // or UIDevice.current.name (see warning below) let activationCode = "VVVVV-VVVVV-VVVVV-VTFVA" // let user type or QR-scan this value let activationOtp = "12345" @@ -267,7 +301,7 @@ Use the following code to create an activation using custom credentials: ```swift // Create a new activation with a given device name and custom login credentials -let deviceName = "Petr's iPhone 7" // or UIDevice.current.name +let deviceName = "Petr's iPhone 7" // or UIDevice.current.name (see warning below) let credentials = [ "username": "john.doe@example.com", "password": "YBzBEM" @@ -290,8 +324,13 @@ powerAuthSDK.createActivation(activation) { (result, error) in } ``` + Note that by using weak identity attributes to create an activation, the resulting activation confirms a "blurry identity". This may greatly limit the legal weight and usability of a signature. We recommend using a strong identity verification before activation can actually be created. + + +Note that if you use `UIDevice.current.name` for a device’s name, your application must include an [appropriate entitlement](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_device-information_user-assigned-device-name); otherwise, the operating system will provide a generic `iPhone` string. + ### Activation via Recovery Code @@ -300,7 +339,7 @@ If the PowerAuth Server is configured to support [Recovery Codes](https://github Use the following code to create an activation using the recovery code: ```swift -let deviceName = "John Tramonta" // or UIDevice.current.name +let deviceName = "John Tramonta" // or UIDevice.current.name (see warning below) let recoveryCode = "55555-55555-55555-55YMA" // User's input let puk = "0123456789" // User's input. You should validate RC & PUK with using PowerAuthActivationCodeUtil @@ -329,6 +368,10 @@ powerAuthSDK.createActivation(activation) { (result, error) in } ``` + +Note that if you use `UIDevice.current.name` for a device’s name, your application must include an [appropriate entitlement](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_device-information_user-assigned-device-name); otherwise, the operating system will provide a generic `iPhone` string. + + ### Customize Activation You can set additional properties to the `PowerAuthActivation` object before any type of activation is created. For example: @@ -483,28 +526,18 @@ if powerAuthSDK.hasValidActivation() { // If no error occurred, process the status if let status = status { - // Activation state: .created, .pendingCommit, .blocked, .removed, .deadlock + // Activation states are explained in detail in "Activation states" chapter below switch status.state { case .pendingCommit: - // Activation is awaiting commit on the server. print("Waiting for commit") case .active: - // Activation is valid and active. print("Activation is active") case .blocked: - // Activation is blocked. You can display unblock - // instructions to the user. print("Activation is blocked") case .removed: - // Activation is no longer valid on the server. - // You can inform the user about this situation and remove - // activation locally. print("Activation is no longer valid") powerAuthSDK.removeActivationLocal() case .deadlock: - // Local activation is technically blocked and no longer - // can be used for the signature calculations. You can inform - // user about this situation and remove activation locally. print("Activation is technically blocked") powerAuthSDK.removeActivationLocal() case .created: @@ -537,7 +570,41 @@ if powerAuthSDK.hasValidActivation() { Note that the status fetch may fail at an unrecoverable error `PowerAuthErrorCode.protocolUpgrade`, meaning that it's not possible to upgrade the PowerAuth protocol to a newer version. In this case, it's recommended to [remove the activation locally](#activation-removal). -To get more information about activation states, check the [Activation States](https://github.com/wultra/powerauth-crypto/blob/develop/docs/Activation.md#activation-states) chapter available in our [powerauth-crypto](https://github.com/wultra/powerauth-crypto) repository. +### Activation states + +This chapter explains activation states in detail. To get more information about activation lifecycle, check the [Activation States](https://github.com/wultra/powerauth-crypto/blob/develop/docs/Activation.md#activation-states) chapter available in our [powerauth-crypto](https://github.com/wultra/powerauth-crypto) repository. + +#### `PowerAuthActivationState.created` + +The activation record is created using an external channel, such as the Internet banking, but the key exchange between the client and server did not happen yet. This state is never reported to the mobile client. + +#### `PowerAuthActivationState.pendingCommig` + +The activation record is created, and the key exchange between the client and server has already taken place, but the activation record on the server requires additional approval before it can be used. This approval is typically performed through an internet banking platform by the client or handled by an authorized representative in a back office system. + +#### `PowerAuthActivationState.active` + +The activation record is created and active. It is ready to be used for typical use-cases, such as generating signatures. + +#### `PowerAuthActivationState.blocked` + +The activation record is blocked and cannot be used for most use-cases, such as generating signatures. While it can be unblocked and activated again, the unblock process cannot be performed locally on the mobile device and requires intervention through an external system, such as internet banking or a back office platform. + +#### `PowerAuthActivationState.removed` + +The activation record is removed and permanently blocked. It cannot be used for generating signatures or ever unblocked. You can inform user about this situation and remove the activation locally. + +#### `PowerAuthActivationState.deadlock` + +The local activation is technically blocked and can no longer be used for signature calculations. You can inform the user about this situation and remove the activation locally. + +The reason why the mobile client is no longer capable of calculating valid signatures is that the logical counter is out of sync between the client and the server. This may happen only if the mobile client calculates too many PowerAuth signatures without subsequent validation on the server. For example: + +- If your application repeatedly constructs HTTP requests with a PowerAuth signature while the network is unreachable. +- If your application repeatedly creates authentication tokens while the network is unreachable. For example, when trying to register for push notifications in the background, without user interaction. +- If you calculate too many offline signatures without subsequent validation. + +In rare situations, this may also happen in development or testing environments, where you’re able to restore the state of the activation on the server from a snapshot. ## Data Signing @@ -1777,7 +1844,7 @@ You can remove EEK from an existing activation if the key is no longer required. ## Share Activation Data -This chapter explains how to share the `PowerAuthSDK` activation state between multiple applications from the same vendor. Before you start, you should read [Prepare Data Sharing](PowerAuth-SDK-for-iOS-Extensions.md#prepare-data-sharing) chapter from PowerAuth SDK for iOS Extensions to configure *Keychain Sharing* and *App Groups* in your Xcode project. +This chapter explains how to share the `PowerAuthSDK` activation state between multiple applications from the same vendor, or between application and its extensions. Before you start, you should read [Prepare Data Sharing](PowerAuth-SDK-for-iOS-Extensions.md#prepare-data-sharing) chapter from PowerAuth SDK for iOS Extensions to configure *Keychain Sharing* and *App Groups* in your Xcode project. This feature is not supported on the macOS Catalyst platform. @@ -1789,13 +1856,10 @@ To share the activation's state just assign an instance of the `PowerAuthSharing ```swift // Prepare the configuration -let configuration = PowerAuthConfiguration() -// Standard configuration -configuration.instanceId = "SharedInstance" -configuration.appKey = "sbG8gd...MTIzNA==" -configuration.appSecret = "aGVsbG...MTIzNA==" -configuration.masterServerPublicKey = "MTIzNDU2Nz...jc4OTAxMg==" -configuration.baseEndpointUrl = "https://localhost:8080/demo-server" +let configuration = PowerAuthConfiguration( + instanceId: Bundle.main.bundleIdentifier!, + baseEndpointUrl: "https://localhost:8080/demo-server", + configuration: "ARDDj6EB6iAUtNm...KKEcBxbnH9bMk8Ju3K1wmjbA==") // Assign sharing configuration configuration.sharingConfiguration = PowerAuthSharingConfiguration( appGroup: "group.your.app.group", @@ -1808,7 +1872,7 @@ let powerAuthSDK = PowerAuthSDK(configuration) The `PowerAuthSharingConfiguration` object contains the following properties: -- `appGroup` is the name of the app group shared between your applications. +- `appGroup` is the name of the app group shared between your applications. Be aware, that the length of app group encoded in UTF-8, should not exceed 26 characters. See [troubleshooting](#length-of-application-group) section for more details. - `appIdentifier` is an identifier unique across your all applications that are supposed to use the shared activation data. You can use your applications' bundle identifiers or any other identifier that can be then processed in all your applications. Due to technical limitations, the length of the identifier must not exceed 127 bytes, if represented in UTF-8. - `keychainAccessGroup` is an access group for keychain sharing. @@ -2038,10 +2102,6 @@ let powerAuthSDK = PowerAuthSDK( ) ``` - -Note that since SDK version `0.18.0`, changing `PowerAuthClientConfiguration` no longer affects networking for previously instantiated `PowerAuthSDK` objects. - - ### Debugging The debug log is by default turned off. To turn it on, use the following code: @@ -2237,3 +2297,15 @@ The tvOS SDK is not required by default since the SDK version 1.7.7. If your bui ```sh pod cache clean 'PowerAuthCore' --all ``` + +### Length of application group + +In case you use the [Activation data sharing](#share-activation-data) feature, the length of the application group encoded in UTF-8 must not exceed **26 characters**. This limitation exists because the feature relies on named shared memory objects, and iOS imposes an undocumented restriction on the length of such object names. + +The total length is limited to 31 characters, but the shared memory object name must be prefixed with your app group, separated by a period (.), to function properly across your applications. We chose to use a 4-character long shared memory object name, generated from the PowerAuthSDK’s instance identifier. As a result, the actual limit for your app group name is: + +``` +31 - 1 - 4 = 26 +``` + +You can extend the length of the application group slightly by providing your own `sharedMemoryIdentifier` in the `PowerAuthSharingConfiguration`. In theory, this allows you to use an app group name of up to 29 characters, leaving 1 character for the shared memory identifier. However, this is generally not recommended. A custom identifier should only be used if your application already employs shared memory and the SDK’s generated identifier conflicts with your existing shared memory objects. diff --git a/docs/PowerAuth-SDK-for-watchOS.md b/docs/PowerAuth-SDK-for-watchOS.md index c8ffe7a0..4df76ed6 100644 --- a/docs/PowerAuth-SDK-for-watchOS.md +++ b/docs/PowerAuth-SDK-for-watchOS.md @@ -173,13 +173,10 @@ class InterfaceController: WKInterfaceController { }() private static func setupPowerAuth() -> PowerAuthWatchSDK { - let config = PowerAuthConfiguration() - config.instanceId = "your-ios-app-bundle-name"; - config.appKey = "sbG8gd...MTIzNA==" - config.appSecret = "aGVsbG...MTIzNA==" - config.masterServerPublicKey = "MTIzNDU2Nz...jc4OTAxMg==" - // URL is optional, the current version of Watch SDK doesn't perform its own networking. - config.baseEndpointUrl = "https://localhost:8080/demo-server" + let config = PowerAuthConfiguration( + instanceId: Bundle.main.bundleIdentifier!, + baseEndpointUrl: "https://localhost:8080/demo-server", + configuration: "ARDDj6EB6iAUtNm...KKEcBxbnH9bMk8Ju3K1wmjbA==") return PowerAuthWatchSDK(configuration: config)! }