Skip to content

Android: users are logged out after updating to 5.11.2 or 5.11.3 from react-native-auth0 5.4.0 or older #1696

Open

Description

@eduardo-santos-tribia

Checklist

Description

After updating an app from react-native-auth0 3.2.1 to 5.11.2, every Android user is logged out on the first launch. getCredentials() rejects with CRYPTO_EXCEPTION ("A change on the Lock Screen security settings have deemed the encryption keys invalid and have been recreated...") and the stored credentials are deleted. iOS keeps the login.

It affects apps going straight to 5.11.2 or 5.11.3 from any react-native-auth0 version that bundles Auth0.Android 3.12.1 or older, which is every 3.x and 4.x release and 5.0.0 to 5.4.0. Those versions protect the credentials with an RSA key that only allows PKCS1 padding. Updating to 5.9.0 to 5.11.1 (Auth0.Android 3.20.0 and 3.21.0, both tested) migrates that key to OAEP and keeps the login. 5.11.2 (Auth0.Android 3.21.1) and 5.11.3 (3.21.2) delete it instead.

Expected: the login survives the update, as it does when updating to 5.11.1.

Cause, in Auth0.Android 3.21.1 (CryptoUtil.java at 3.21.1):

  1. RSADecrypt: Cipher.init with OAEP on the PKCS1-only key throws InvalidKeyException (Keystore INCOMPATIBLE_PADDING_MODE). Since fix(storage): authorize MGF1 digest to prevent INCOMPATIBLE_DEVICE on…3.x Auth0.Android#1048 this branch calls deleteRSAKeys() and deleteAESKeys() (L385-L386) before it throws CryptoException.
  2. tryRecoverCurrentAESKey catches it and calls attemptPKCS1Migration, which exists for exactly this key. The key was just deleted, so findRSAKeyEntry returns null and it logs "No RSA key found for migration".
  3. The keys are deleted again (L648-L651), a new AES key is generated, the stored credentials can't be decrypted, and SecureCredentialsManager clears them.

Auth0.Android 4.2.0 has the same code (L364-L366). Before #1048, RSADecrypt in 3.20.0 turned the same exception into IncompatibleDeviceException without deleting anything, so the migration still found the key.

Why Auth0.Android's tests pass: the PKCS1 migration tests in CryptoUtilTest (shouldDetectAndMigratePKCS1KeyToOAEP, shouldAllowMultipleRetrievalsAfterMigration, shouldTriggerPKCS1MigrationWhenRSADecryptThrowsProviderException) stub RSADecrypt on the spy (L1761), so the real deletion never runs, and the key is still reported as present (L1763). shouldRecreateKeysAndThrowCryptoExceptionOnInvalidKeyExceptionWhenTryingToRSADecrypt (L901) tests the deletion on its own. No test combines the two, and on a device they always run together.

Suggested fix (in Auth0.Android): don't delete keys in RSADecrypt's InvalidKeyException / InvalidAlgorithmParameterException branch; only throw CryptoException. RSADecrypt's only caller is tryRecoverCurrentAESKey (L628), which already deletes both keys at L648-L651 when the PKCS1 migration doesn't succeed. Keys with a mismatched MGF1 digest (auth0/Auth0.Android#1016) would still be regenerated, and PKCS1 keys would be migrated first. A regression test could stub only Cipher.init, as the L901 test does, instead of RSADecrypt, and assert that getAESKey() returns the migrated key. react-native-auth0 would then need a 5.11.x release with the fixed Auth0.Android.

Reproduction

Reproduces every time.

With react-native-auth0 (our app, release builds, Android 16 emulator):

  1. Install the app built with react-native-auth0 3.2.1 (React Native 0.77.3), log in.
  2. Update it in place (adb install -r) to the build with react-native-auth0 5.11.2 (React Native 0.88.0), launch.
  3. getCredentials() rejects with CRYPTO_EXCEPTION and the user is back on the login screen. Updating the same way on iOS keeps the login.

With Auth0.Android only (no React Native, attached auth0-repro.zip). A minimal app that uses only SecureCredentialsManager, with a fake long-lived access token, so no login or network:

  1. Build it with com.auth0.android:auth0:2.10.2, install, launch. It calls saveCredentials(new Credentials("", "access-token", "Bearer", null, inOneYear, "openid")).
  2. Launch again: getCredentials() returns the credentials.
  3. Change the dependency to 3.21.1 (only the SecureCredentialsManager constructor changes; 4.x also needs AGP 9 and compileSdk 37), update in place with adb install -r, launch. getCredentials() fails:
    CredentialsManagerException: A change on the Lock Screen security settings have deemed the encryption keys invalid and have been recreated. Any previously stored content is now lost. Please try saving the credentials again.
    Caused by: CryptoException: The encryption keys changed recently. You need to re-encrypt something first.
    
  4. Launch again: No Credentials were previously set.

Results with the minimal app (Android 16 / API 36 emulator; the starred rows were also run on Android 11 / API 30 and Android 12 / API 31, with the same results):

Auth0.Android update path react-native-auth0 with that version Result
2.10.2 → 3.21.1 ★ 3.2.1 → 5.11.2 Credentials deleted
2.10.2 → 3.21.2 3.2.1 → 5.11.3 Credentials deleted
2.10.2 → 4.2.0 – Credentials deleted
2.10.2 → 4.1.0 3.2.1 → 6.0.0-beta.0 Migrated, credentials kept
2.10.2 → 3.21.0 3.2.1 → 5.10.0 to 5.11.1 Migrated, credentials kept
2.10.2 → 3.20.0 ★ 3.2.1 → 5.9.x Migrated, credentials kept
2.10.2 → 3.20.0 → 3.21.1 3.2.1 → 5.9.x → 5.11.2 Kept (3.20.0 already migrated the key)
3.21.1 only (save, then read) 5.11.2 only Works

CryptoUtil log on the first launch after updating to 3.21.1 (Android 16, stack frames removed; our app logs the same sequence):

E/CryptoUtil: RSA key rejected the cipher parameters (likely MGF1 digest mismatch on Keystore2). Recreating key.
E/CryptoUtil: java.security.InvalidKeyException: Keystore operation failed
E/CryptoUtil: Caused by: android.security.KeyStoreException: Incompatible padding mode (internal Keystore code: -11 ...)
E/CryptoUtil:     2: Error::Km(r#INCOMPATIBLE_PADDING_MODE)) (public error code: 13 internal Keystore code: -11)
D/CryptoUtil: Deleting the existing RSA key pair from the KeyStore.
D/CryptoUtil: OAEP decryption failed, attempting PKCS1 migration
D/CryptoUtil: com.auth0.android.authentication.storage.CryptoException: The RSA key's authorized parameters are incompatible with the current cipher. The keys have been recreated; please retry.
D/CryptoUtil: No RSA key found for migration
W/CryptoUtil: Could not recover AES key. Deleting corrupted keys.
D/CryptoUtil: Deleting the existing RSA key pair from the KeyStore.
D/CryptoUtil: New AES key generated and stored
D/SecureCredentialsManager: Credentials were just removed from the storage

Android 11 logs the same sequence (KeyStoreException: Incompatible padding mode), so this isn't limited to Keystore2, even though the log message mentions it.

For comparison, Auth0.Android 3.20.0 on the same data:

E/CryptoUtil: The device can't decrypt input using a RSA Key.
D/CryptoUtil: OAEP decryption failed, attempting PKCS1 migration
D/CryptoUtil: PKCS1 migration successful - deleting old keys
D/CryptoUtil: Deleting the existing RSA key pair from the KeyStore.
D/CryptoUtil: AES key re-encrypted with OAEP and stored

auth0-repro.zip

Additional context

  • Auth0.Android 4.2.0 (22 Oct) has the same bug, so a 6.x release that moves from 4.1.0 to 4.2.0 will log these users out too.
  • The Auth0.Android 4.2.0 log follows the same path as 3.21.1, from "Recreating key" to "Credentials were just removed from the storage". Auth0.Android 5.0.0-beta.0 predates [Snyk] Upgrade react-native-screens from 4.5.0 to 4.6.0 #1092, but sync : Sync main to v5_developement Auth0.Android#1105 syncs main into the 5.x branch, so its next release will likely be affected too.
  • Our workaround until a fix ships: a one-time migration in Application.onCreate, before React Native starts. If the RSA key is PKCS1-only, it decrypts the stored AES key with PKCS1, recreates the RSA key with the 3.21.1 spec (OAEP, MGF1 digests on API 35+), and re-wraps the AES key with OAEP.
  • We use Auth0Provider with the default storage, no biometrics (localAuthenticationOptions) and useDPoP: false. Our code doesn't clear credentials when getCredentials() fails; the SDK clears them before the promise rejects.

react-native-auth0 version

5.11.2 and 5.11.3 (updating from 3.2.1)

React Native version

0.88.0 (also reproduced without React Native, see Reproduction)

Expo version

No response

Platform

Android

Platform version(s)

Android 11 (API 30), 12 (API 31) and 16 (API 36), on emulators with Google APIs arm64 images

Activity

  1. subhankarmaiti commented on Oct 23, 2026

    @subhankarmaiti
    Contributor

    Thanks for reporting, @utkrishtsahu is working on it to fix the issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugThis points to a verified bug in the code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions