Skip to main content
Version: 5.0

Troubleshooting

Common Problems

When implementing Identity Vault, you need to avoid scenarios in your application where two native calls are made at the same. Here are a few common patterns with suggestions on how to solve for them.

  1. Calling new Vault() in a Constructor
  2. Calling `new Vault(config)
  3. Using Auth Guards and lockafterbackgrounded
  4. Using Auth Guards and unlockVaultOnLoad
  5. Not handling error code 0
  6. Missing an await on a vault method
  7. Not using try/catch
  8. Not testing common scenarios
  9. User canceled auth attempt
  10. Biometric prompt does not show

Calling new Vault() in a Constructor

A call to new Vault() involves native code and will take some time to complete. During that time there is usually other constructors and startup logic (like an Auth Guard) that will also attempt to call the Vault (for example to get a token). This will result in an error:


_10
export class VaultService {
_10
constructor() {
_10
this.vault = new Vault(this.config);
_10
}
_10
}

The Fix

Instead, ensure Vault creation happens serially by creating the Vault using an APP_INITIALIZER (for Angular) or by starting your app on a page that establishes the Vault before proceeding.

In your app.module.ts:


_11
const appInitFactory =
_11
(vaultService: VaultService): (() => Promise<void>) =>
_11
async () =>
_11
await vaultService.init();
_11
_11
@NgModule({
_11
...
_11
providers: [
_11
{ provide: APP_INITIALIZER, useFactory: appInitFactory, deps: [VaultService], multi: true }],
_11
...
_11
})

In the above example the init method will create the Vault (and perform any other setup needed). Using APP_INITIALIZER will ensure that it is called before any other constructor is called or any routing logic is called.

Use Initialize

Instead of calling new Vault(config) use a combination of new Vault() and await Vault.initialize(config). The later will ensure that you can await the completion of vault initialization before you make any calls to the vault. This is a common mistake where you get native errors on startup of an application.

Using Auth Guards and lockafterbackgrounded

The lockAfterBackgrounded property will ensure that the Vault is locked when the application is resumed from the background. However, your auth guard is likely trying to read from the Vault at the same time. This will result in an error.

The Fix

There are a few options:

  1. On resuming an app, you can route to a page which establishes its auth state.
  2. Remove lockafterbackgrounded and implement your own solution provide this feature.
  3. In the auth guard, await a method which will delay for a second while the app is resuming

Option 1 would be preferred as its implementation is simple and has the added benefit of avoiding showing any private information on the page during the time the auth status is being established.

Using Auth Guards and unlockVaultOnLoad

The unlockVaultOnLoad property will ensure that an unlock attempt is made when the application is started. However, your auth guard or startup logic may also try to read from the Vault at the same time resulting in an error.

The Fix

There are a few options:

  1. On starting an app, you can route to a page which establishes its auth state.
  2. Remove unlockVaultOnLoad and implement your own solution provide this feature.

Option 2 is usually the easiest here as your auth guard will likely try to read the Vault and it will need to unlock it to do so. In most cases removing the unlockVaultOnLoad property is all that is needed.

Not handling error code 0

Identity Vault interfaces with native libraries that are device specific and depending on the device there may be flaws in the devices implementation. As a fallback mechanism you should handle the Unknown Vault Error by clearing the Vault and routing the app to a login page. Without this logic your user could be stuck unable to login and would need to delete the app and reinstall.

Missing an await on a Vault method

All Vault methods are asynchronous and if you call 2 methods without awaiting then you will get unknown results. For example, calling setValue and getValue like:


_10
this.vault.setValue("foo", "bar");
_10
await this.vault.getValue("foo"); // Will this return bar?

Instead always use await:


_10
await this.vault.setValue("foo", "bar");
_10
await this.vault.getValue("foo"); // This will return "bar" (maybe)

However, there is a problem in the above code, which leads to the next common mistake...

Not using try/catch

What happens if you need to get a value from a biometric Vault and the user cancels the prompt? or there is another error?

These are common scenarios that you need to cater for using try, catch and finally.


_12
try {
_12
const value = await this.vault.getValue("foo");
_12
} catch (error) {
_12
// Handle specific Vault Error
_12
switch (e.code) {
_12
case VaultErrorCodes.UserCanceledInteraction:
_12
// maybe retry? or take them back to login
_12
break;
_12
default:
_12
throw error;
_12
}
_12
}

Not testing common scenarios

There are many ways a user can interact with biometrics that you may not have tested or considered. Try to handle these scenarios in your application when the user:

  1. Adds a fingerprint or face
  2. Removes a fingerprint or face
  3. Disables biometrics for your app
  4. Removes the lock PIN of their device (or adds one)
  5. Has an Android device with only weak Face Biometrics
  6. Backgrounds the app during the biometric prompt
  7. Resumes the app after backgrounding the app during the biometric prompt
  8. Attempts the biometric prompt too many times
  9. Restores the app on a new device from a backup
  10. Is locked out of biometrics because of too many failed attempts in another app

User canceled auth attempt

The error {code: 8, message: 'User canceled auth attempt.'} on startup is often caused by 2 simultaneous attempts to use a biometric vault - one attempt is successful (showing the biometric prompt) and the other is cancelled (because there is already a biometric prompt being shown).

If you have unlockVaultOnLoad set to true then you need to make sure there is no other place in your code that is attempting to read or unlock the vault on startup of the application.

If you have lockAfterBackgrounded set to a value then you need to make sure that when your application is resumed (opens after being backgrounded) that there is no other place in your code that is attempting to read or unlock the vault. This could include Auth Guard in Angular, http intercepts using the vault to access a token, etc.

Biometric Prompt does not show

If you are reading or unlocking a vault that is of type VaultType.DeviceSecurity / DeviceSecurityType.Biometrics and the biometric prompt does not show, then it is likely that the vault on the device was previously saved as type VaultType.SecureStorage. Remember that your vault configuration is only used if the device does not already have a vault. So, if you have a previously run your app with a different configuration then you may run into this situation.

To test if this is the case try changing the key of your vault and see if it now works.

Known Device Issues

Due to the nature of device fragmentation on Android, there could be scenarios where not all security features are supported on certain devices. View the table below for a list of currently known issues:

DeviceKnown Issue
Samsung S9 / Samsung S9+Using a weak biometric (face) prompt with a system passcode is not supported on this device. The prompt will always show the system passcode prompt.
Devices using Gesture NavigationHide screen on background will not work in the recent apps switcher due to a bug in the Android gesture navigation.