Device Activation
After you configure the SDK, you are ready to make your first activation.
Activation via Activation Code
The original activation method uses a one-time activation code generated in PowerAuth Server. To create an activation using this method, some external application (Internet banking, ATM application, branch/kiosk application) must generate an activation code for you and display it (as text or in a QR code).
Use the following code to create an activation once you have an activation code:
final name = "Petr's iPhone"; // users phone name
final activationCode = "VVVVV-VVVVV-VVVVV-VTFVA"; // let user type or QR-scan this value
// Create activation object with given activation code.
final activation = PowerAuthActivation.fromActivationCode(activationCode: activationCode, name: name);
try {
final result = await powerAuth.createActivation(activation);
// No error occurred, proceed to credentials entry (PIN prompt, Enable Biometry, ...) and persist the activation
// The 'result' contains 'activationFingerprint', representing the combination of device and server public keys - it may be used as visual confirmation
} on PowerAuthException catch (e) {
// handle powerauth exception
} catch (e) {
// unknown exception
}
Additional Activation OTP
If an additional activation OTP is required to complete the activation, then use the following code to configure the PowerAuthActivation object:
final name = "Petr's iPhone"; // users phone name
final activationCode = "VVVVV-VVVVV-VVVVV-VTFVA"; // let user type or QR-scan this value
// Create activation object with given activation code.
final activation = PowerAuthActivation.fromActivationCode(
activationCode: activationCode,
name: name,
additionalActivationOtp: '123456' // OTP retrieved via other channel (SMS, for example)
);
// The rest of the activation routine is the same.
Be aware that OTP can be used only if the activation is configured for ON_KEY_EXCHANGE validation on the PowerAuth server. See our crypto documentation for details.
Activation via Custom Credentials
You may also create an activation using any custom login data - it can be anything that the server can use to obtain the user ID to associate with a new activation. Since the credentials are custom, the server’s implementation must be able to process such a request. The custom activation no longer requires a custom activation endpoint.
Use the following code to create an activation using custom credentials:
// Create a new activation with a given device name and custom login credentials
final name = "Petr's iPhone"; // users phone name
final credentials = {
"username": "[email protected]",
"password": "YBzBEM"
};
// Create activation object with given credentials.
final activation = PowerAuthActivation.fromIdentityAttributes(
identityAttributes: credentials,
name: name,
);
// Create a new activation with the just-created activation object
try {
final result = await powerAuth.createActivation(activation);
// No error occurred, proceed to credentials entry (PIN prompt, Enable Biometry, ...) and persist the activation
// The 'result' contains 'activationFingerprint', representing the combination of device and server public keys - it may be used as visual confirmation
} on PowerAuthException catch (e) {
// handle powerauth exception
} catch (e) {
// unknown exception
}
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.
Activation via OpenID Connect
You may also create an activation using OIDC protocol:
// Create a new activation with OIDC parameters
final name = "Petr's iPhone"; // users phone name
// Get the following information from your OpenID provider
final oidcParameters = PowerAuthOIDCParameters(
providerId: "my-provider-id",
code: "1234567890abcdef",
nonce: "K1mP3rT9bQ8lV6zN7sW2xY4dJ5oU0fA1gH29o",
codeVerifier: "G3hsI1KZX1o~K0p-5lT3F7yZ4...6yP8rE2wO9n" // optional
);
// Create activation object with OIDC parameters.
final activation = PowerAuthActivation.fromOIDC(
oidcParameters: oidcParameters,
name: name,
);
// Create a new activation with the just-created activation object
try {
final result = await powerAuth.createActivation(activation);
// No error occurred, proceed to credentials entry (PIN prompt, Enable Biometry, ...) and persist the activation
} on PowerAuthException catch (e) {
// handle powerauth exception
} catch (e) {
// unknown exception
}
Customize Activation
You can set additional properties to the PowerAuthActivation object before any type of activation is created. For example:
// Custom attributes that can be processed before the activation is created on the PowerAuth Server.
// The dictionary may contain only values that can be serialized to JSON.
final customAttributes = {
"isNowPrimaryActivation" : true,
"otherActivationIds" : [
"e43f5f99-e2e9-49f2-bcae-5e32a5e96d22",
"41dd704c-65e6-4d4b-b28f-0bc0e4eb9715"
]
};
// Create the activation object
final activation = PowerAuthActivation.fromActivationCode(
activationCode: "45AWJ-BVACS-SBWHS-ABANA",
name: "deviceName",
customAttributes: customAttributes,
extras: "EXTRA_FLAGS" // Extra flags that will be associated with the activation record on PowerAuth
);
// Create a new activation as usual
try {
final result = await powerAuth.createActivation(activation);
// continue with the flow
} catch (e) {
// process eror
}
Persisting Activation Data
After you create an activation using one of the methods mentioned above, you need to persist the activation to use the provided user credentials to store the activation data on the device.
final authentication = PowerAuthAuthentication.persistWithPassword(
await PowerAuthPassword.fromString("1234"),
);
try {
await powerAuth.persistActivation(authentication);
} catch (e) {
// Process failure.
}
This creates an activation with possession and knowledge factors. To enable biometry while persisting the activation, use:
final authentication = PowerAuthAuthentication.persistWithPasswordAndBiometry(
password: await PowerAuthPassword.fromString("1234"),
biometricPrompt: PowerAuthBiometricPrompt(
// Required on Android when authenticateOnBiometricKeySetup is true.
promptTitle: "Please authenticate with biometry",
promptMessage: "Please authenticate to create an activation supporting biometry",
),
);
try {
await powerAuth.persistActivation(authentication);
} catch (e) {
// Process failure, including biometric cancellation or a server error.
}
You can omit biometricPrompt on iOS. You can also omit it on Android when authenticateOnBiometricKeySetup is false.
Validating User Inputs
The mobile SDK provides a couple of functions in the PowerAuthActivationCodeUtil helper, helping with user input validation. You can:
- Parse activation code when it’s scanned from a QR code
- Validate the whole code at once
- Auto-correct characters typed on the fly
Validating Scanned QR Code
To parse an activation code scanned from a QR code, use PowerAuthActivationCodeUtil.parseActivationCode(code). You can provide the code with or without a legacy signature suffix. The function validates the activation-code format and returns the activation code without the suffix:
final scannedCode = "VVVVV-VVVVV-VVVVV-VTFVA#aGVsbG8......gd29ybGQ=";
try {
final parsed = await PowerAuthActivationCodeUtil.parseActivationCode(
scannedCode,
);
final activationCode = parsed.activationCode;
// Use activationCode to create the activation.
} catch (e) {
// The activation code is not valid.
}
PowerAuth Mobile SDK versions older than 2.0 allowed applications to verify the signature suffix. This is no longer possible because post-quantum signatures are too large to embed in a QR code. If an activation code with a signature is used in the activation process, the signature suffix is ignored. Use PowerAuthActivationCodeUtil.parseActivationCode() only to validate the scanned code and strip the suffix.
Validating Entered Activation Code
To validate an activation code at once, you can call the PowerAuthActivationCodeUtil.validateActivationCode() function. You have to provide the code without the signature part. For example:
final isValid = await PowerAuthActivationCodeUtil.validateActivationCode("VVVVV-VVVVV-VVVVV-VTFVA");
final isInvalid = await PowerAuthActivationCodeUtil.validateActivationCode("VVVVV-VVVVV-VVVVV-VTFVA#aGVsbG8gd29ybGQ=");
If your application is using your own validation, then you should switch to the functions provided by the SDK. All activation codes contain a checksum, so it’s possible to detect mistyped characters before you start the activation. Check our Activation Code documentation for more details.
Auto-Correcting Typed Characters
You can implement auto-correcting of typed characters by using PowerAuthActivationCodeUtil.correctTypedCharacter() function in screens, where the user is supposed to enter an activation code. This technique is possible due to the fact that Base32 is constructed so that it doesn’t contain visually confusing characters. For example, 1 (number one) and I (capital I) are confusing, so only I is allowed. The benefit is that the provided function can correct typed 1 and translate it to I.
Here’s an example of how to iterate over the string and validate it character by character:
/// Returns corrected code
Future<String> validateAndCorrectCharacters(String code) async {
var result = "";
for (var i = 0; i < code.length; i++) {
try {
final corrected = await PowerAuthActivationCodeUtil.correctTypedCharacter(code.codeUnitAt(i));
result += String.fromCharCode(corrected);
} catch (e) {
print('invalid character: ${code.codeUnitAt(i)}');
}
}
print('Corrected: $result');
return result;
}
If the UI needs validation without correction, call validateTypedCharacter() with the character’s Unicode code point:
final isAllowed = await PowerAuthActivationCodeUtil.validateTypedCharacter(
typedCharacter.runes.single,
);
validateTypedCharacter() only checks whether the character is already valid. Use correctTypedCharacter() when lowercase and visually ambiguous characters should be normalized.