Skip to main content
Version: 4.4.x.x RR (Android, iOS) / 4.5.x.x RR (Flutter) / 5.x.x.x RR (React Native)

Troubleshooting guide

Nevis Authentication Cloud

Error sending registration SendUafResponse. Status code 403

You are likely using the wrong SDK configuration builder, which is intended for On-premise backends. Verify that you are using the correct auth cloud builder as stated in Authentication Cloud Backend configuration.

General - If the app is not working

Does the mobile phone meet the minimum OS requirements?

For Android devices, Android 7 or higher is required.

For Apple devices, iOS 14 or higher is required.

Does the mobile phone have a trusted execution environment?

Your mobile phone needs a secure Trusted Execution Environment (TEE) for the Nevis Mobile Authentication SDK to work. Some smart devices do not have a TEE required for cryptographic calculations and storage as part of a secure authentication process, such as Google Pixel 1, Nexus 5, Mate 9, Galaxy A5, and the iPod Touch.

Does the mobile phone have lock-screen set up?

Without a lock on the device, security is compromised. The device requires device passcode (PIN, password, gesture) to unlock the home screen.

Does your Android application have a dependency with BouncyCastle?

The SDK depends on the jdk15to18 BouncyCastle delivery. If your application uses another distribution (like jdk18n) this can be problematic when the SDK does some cryptographic operations during initialization.

Excluding one of the dependencies can solve the issue. For example, if you want to keep the BouncyCastle delivered with your application, you can exclude the dependency from the SDK when declaring it in your build.gradle file:

Remove transitive dependency
implementation("ch.nevis:nevis-mobile-authentication-sdk-android:${NEVIS_MOBILE_AUTHENTICATION_SDK_ANDROID_VERSION}") {
exclude group: 'org.bouncycastle', module: 'bcprov-jdk15to18'
exclude group: 'org.bouncycastle', module: 'bcpkix-jdk15to18'
}

You can get the dependencies of a module by using the gradle command-line:

Get transitive dependencies
gradle :<app module name>:dependencies 

DeviceProtectionError when testing a release build on a physical device

Symptom: The app initializes successfully in debug mode but throws DeviceProtectionError in release mode when deployed directly to a physical device via USB. The error does not occur after installing the same build through TestFlight or another distribution channel.

Cause: The release SDK contains active tamper guards, including a debugger detection guard. When a release build is deployed from an IDE or via the command line while the device is connected via USB (for example, using flutter run --release, an Xcode run scheme, or Android Studio's run action), the developer tooling remains attached to the app process. The debugger detection guard detects this and raises DeviceProtectionError, even on a real, non-jailbroken, non-rooted device. This is intentional behavior — the guard cannot distinguish between a legitimate developer workflow and an attacker using a debugger to reverse-engineer the app.

Resolution: Distribute the release build through a channel that does not attach developer tooling:

  • iOS: Use TestFlight or export an ad hoc IPA and install it via Xcode Devices & Simulators or Apple Configurator.
  • Android: Build the APK and install it via adb install <app>.apk without keeping the device in a run session, or use Firebase App Distribution.

See SDK flavors for a description of what protection mechanisms are active in the release flavor, and Publication: Testing release builds during development for a broader discussion.

Is my key material stored in Android StrongBox?

The following code snippet will allow you to check whether the mobile device allows to store the keys with the algorithm requirements of the SDK in StrongBox. It requires API 31 or later for the check to work:

Android StrongBox verification
fun printKeys() {
val androidKeyStore = KeyStore.getInstance("AndroidKeyStore")
androidKeyStore.load(
null,
null
)
androidKeyStore.aliases().toList().forEach { alias ->
val key = androidKeyStore.getKey(alias, null)
if (key is PrivateKey) {
println("***** alias: $alias")
val keyInfo = KeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore")
.getKeySpec(key, KeyInfo::class.java)
val securityLevel = keyInfo.securityLevel
println("****** stored in StrongBox: " + (securityLevel == KeyProperties.SECURITY_LEVEL_STRONGBOX))
}
}
}