Skip to content

Commit

Permalink
Android: #642: Asynchronous PowerAuthSDK.persistActivation(...) methods
Browse files Browse the repository at this point in the history
  • Loading branch information
hvge committed Feb 18, 2025
1 parent a51c8bb commit 3820e53
Show file tree
Hide file tree
Showing 8 changed files with 646 additions and 229 deletions.
6 changes: 6 additions & 0 deletions docs/Migration-from-1.9-to-1.10.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ PowerAuth Mobile SDK in version `1.10.0` provides the following improvements:

- The following methods in `PowerAuthSDK` class are deprecated:
- `changePasswordUnsafe()` - use asynchronous `changePassword()` as a replacement.
- `persistActivationWithAuthentication()` - use asynchronous variant with `IPersistActivationListener` as a callback parameter.
- `persistActivationWithPassword()` - use asynchronous variant with `IPersistActivationListener` as a callback parameter.
- `persistActivation(..., IPersistActivationWithBiometricsListener)` - use asynchronous method with `IPersistActivationListener` as a callback parameter.

- The following methods in `PowerAuthKeychainConfiguration` are now deprecated:
- `isLinkBiometricItemsToCurrentSet()` - use `PowerAuthBiometricConfiguration.isInvalidateBiometricFactorAfterChange()` instead.
Expand All @@ -26,6 +29,9 @@ PowerAuth Mobile SDK in version `1.10.0` provides the following improvements:
- `Builder.authenticateOnBiometricKeySetup()` - use equal method in `PowerAuthBiometricConfiguration.Builder` instead.
- `Builder.enableFallbackToSharedBiometryKey()` - use equal method in `PowerAuthBiometricConfiguration.Builder` instead.

- The following classes and interfaces are now deprecated:
- `IPersistActivationWithBiometricsListener` - use `IPersistActivationListener` instead.

- Due to removed support of recovery codes, the following classes and methods are no longer available:
- Methods removed in `PowerAuthSDK`:
- `createRecoveryActivation()`
Expand Down
112 changes: 43 additions & 69 deletions docs/PowerAuth-SDK-for-Android.md
Original file line number Diff line number Diff line change
Expand Up @@ -552,83 +552,68 @@ try {

After you create an activation using one of the methods mentioned above, you need to persist the activation - to use provided user credentials to store the activation data on the device. Use the following code to do this.

<!-- begin codetabs Kotlin Java -->
```kotlin
// Persist activation using given PIN
val result = powerAuthSDK.persistActivationWithPassword(context, pin)
if (result != PowerAuthErrorCodes.SUCCEED) {
// happens only in case SDK was not configured or activation is not in the state to be persisted
}
```
```java
// Persist activation using given PIN
int result = powerAuthSDK.persistActivationWithPassword(context, pin);
if (result != PowerAuthErrorCodes.SUCCEED) {
// happens only in case SDK was not configured or activation is not in the state to be persisted
}
```
<!-- end -->

This code has created activation with two factors: possession (key stored using a key derived from a device fingerprint) and knowledge (password, in our case, a simple PIN code). If you would like to enable biometric authentication support at this moment, use the following code instead of the one above:

<!-- begin codetabs Kotlin Java -->
```kotlin
// Persist activation using given PIN and ad-hoc generated biometric related key
powerAuthSDK.persistActivation(context, fragment, "Enable Biometric Authentication", "To enable biometric authentication, use the biometric sensor on your device.", pin, object: IPersistActivationWithBiometricsListener {
override fun onBiometricDialogCancelled() {
// Biometric enrolment cancelled by user
val authentication = PowerAuthAuthentication.persistWithPassword(pin)
val cancelable = powerAuthSDK.persistActivationWithAuthentication(context, authentication, object: IPersistActivationListener {
override fun onPersistActivationSucceeded() {
// Success
}

override fun onBiometricDialogSuccess() {
// success, activation has been persisted
override fun onPersistActivationFailed(error: PowerAuthErrorException) {
// Failure
}

override fun onBiometricDialogFailed(error: PowerAuthErrorException) {
// failure, typically as a result of API misuse, or a biometric authentication failure
override fun onPersistActivationCancelled(userCancel: Boolean) {
if (userCancel) {
// user cancelled the biometric authentication dialog
} else {
// Your application canceled the provided cancelable object
}
}
})
```
```java
// Persist activation using given PIN and ad-hoc generated biometric related key
powerAuthSDK.persistActivation(context, fragment, "Enable Biometric Authentication", "To enable biometric authentication, use the biometric sensor on your device.", pin, new IPersistActivationWithBiometricsListener() {
@Override
public void onBiometricDialogCancelled() {
// Biometric enrolment cancelled by user

This code has created activation with two factors: possession (key stored using a key derived from a device fingerprint) and knowledge (password, in our case, a simple PIN code). If you would like to enable biometric authentication support at this moment, use the following code instead of the one above:

```kotlin
// Prepare biometric prompt.
val biometricPrompt = PowerAuthBiometricPrompt.Builder(parentFragment) // You can also use fragment activity in the constructor
.setTitle("Enable Biometric Authentication")
.setDescription("To enable biometric authentication, use the biometric sensor on your device.")
.build()
// Persist activation using given PIN and biometry
val authentication = PowerAuthAuthentication.persistWithPasswordAndBiometry(pin, biometricPrompt)
val cancelable = powerAuthSDK.persistActivationWithAuthentication(context, authentication, object: IPersistActivationListener {
override fun onPersistActivationSucceeded() {
// Success
}

@Override
public void onBiometricDialogSuccess() {
// success, activation has been persisted
override fun onPersistActivationFailed(error: PowerAuthErrorException) {
// Failure
}

@Override
public void onBiometricDialogFailed(@NonNull PowerAuthErrorException error) {
// failure, typically as a result of API misuse, or a biometric authentication failure
override fun onPersistActivationCancelled(userCancel: Boolean) {
if (userCancel) {
// user cancelled the biometric authentication dialog
} else {
// Your application canceled the provided cancelable object
}
}
});
})
```
<!-- end -->

Also, you can use the following code to create activation with the best granularity control:
If `PowerAuthSDK` is configured to do not authenticate on biometric key setup (e.g. `PowerAuthBiometricConfiguration` has `authenticateOnBiometricKeySetup` set to `false`), then you can use a "dummy" biometric prompt to simplify your code:

<!-- begin codetabs Kotlin Java -->
```kotlin
val authentication = PowerAuthAuthentication.persistWithPasswordAndBiometry(pin, biometryFactorRelatedKey)
val result = powerAuthSDK.persistActivationWithAuthentication(context, authentication)
if (result != PowerAuthErrorCodes.SUCCEED) {
// happens only in case SDK was not configured or activation is not in the state to be persisted
}
```
```java
PowerAuthAuthentication authentication = PowerAuthAuthentication.persistWithPasswordAndBiometry(pin, biometryFactorRelatedKey);
int result = powerAuthSDK.persistActivationWithAuthentication(context, authentication);
if (result != PowerAuthErrorCodes.SUCCEED) {
// happens only in case SDK was not configured or activation is not in the state to be persisted
}
// Prepare biometric prompt.
val biometricPrompt = PowerAuthBiometricPrompt.noPromptForBiometricKeySetup(parentFragment)
// Persist activation using given PIN and biometry
val authentication = PowerAuthAuthentication.persistWithPasswordAndBiometry(pin, biometricPrompt)
val cancelable = powerAuthSDK.persistActivationWithAuthentication(context, authentication, object: IPersistActivationListener {
// Example is the same as above
})
```
<!-- end -->

Note that you currently need to obtain the biometry factor-related key yourself - you have to use `BiometricPrompt.CryptoObject` or integration with Android `KeyStore` to do so.

### Validating User Inputs

Expand Down Expand Up @@ -1634,7 +1619,6 @@ powerAuthSDK.addBiometryFactor(context, fragment, "Enable Biometric Authenticati

By default, PowerAuth SDK asks the user to authenticate with the biometric sensor also during the setup procedure (or during the [activation persist](#persisting-activation-data)). To alter this behavior, use the following code to change the `PowerAuthBiometricConfiguration` provided to the `PowerAuthSDK` instance:

<!-- begin codetabs Kotlin Java -->
```kotlin
val biometricConfig = PowerAuthBiometricConfiguration.Builder()
.authenticateOnBiometricKeySetup(false)
Expand All @@ -1644,16 +1628,6 @@ val powerAuthSDK = PowerAuthSDK.Builder(configuration)
.biometricConfiguration(biometricConfig)
.build(getApplicationContext())
```
```java
PowerAuthBiometricConfiguration biometricConfig = new PowerAuthBiometricConfiguration.Builder()
.authenticateOnBiometricKeySetup(false)
.build();
// Apply keychain configuration
PowerAuthSDK powerAuthSDK = new PowerAuthSDK.Builder(configuration)
.biometricConfiguration(biometricConfig)
.build(getApplicationContext());
```
<!-- end -->

<!-- begin box info -->
Note that the RSA key pair is internally generated for the configuration above. That may take more time on older devices than the default configuration. Your application should display a waiting indicator on its own because SDK doesn't display an authentication dialog during the key-pair generation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@

/**
* Interface used as a callback for persisting the activation with biometric authentication.
*
* @deprecated Interface is deprecated, use {@link io.getlime.security.powerauth.networking.response.IPersistActivationListener} as replacement.
*/
@Deprecated // 1.10.0
public interface IPersistActivationWithBiometricsListener {
/**
* Biometric dialog was cancelled.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2025 Wultra s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.getlime.security.powerauth.networking.response;

import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import io.getlime.security.powerauth.exception.PowerAuthErrorException;

/**
* Listener for persist activation operation.
*/
public interface IPersistActivationListener {
/**
* Called when activation has been successfully persisted on the device.
*/
@MainThread
void onPersistActivationSucceeded();

/**
* Called when failed to persist activation on the device.
*
* @param error error occurred during the operation
*/
@MainThread
void onPersistActivationFailed(@NonNull PowerAuthErrorException error);

/**
* Called when persist activation operation failed due to cancellation of biometric authentication dialog.
*
* @param userCancel If parameter is {@code true}, then the dialog was canceled by the user. The {@code false}
* value means that authentication request was canceled by your code, by calling {@code cancel()}
* on provided cancelable object.
*/
@MainThread
void onPersistActivationCancelled(boolean userCancel);
}
Loading

0 comments on commit 3820e53

Please sign in to comment.