Preferences Isn't Secure

Why Preferences Is Not Secure Storage

BookNest's new lab button stores one stand-in session token twice, once the tempting way and once properly (Secure Preferences):

The same token in two stores, in src/js/lab.jsJavaScript
export async function secrets() {
  const token = 'bn_live_7f3a9c21'; // stand-in for a real session token
  await Preferences.set({ key: 'authToken', value: token }); // plain XML: never do this
  await SecureStorage.set('authToken', token); // AES-GCM, key held by the Android Keystore
  return show('secrets', { readBack: await SecureStorage.get('authToken') });
}

Preferences wrote exactly what it was given, as Preferences showed for the cart:

Reading the Preferences file from the debug buildShell
adb -s emulator-5558 shell run-as com.example.booknest cat shared_prefs/CapacitorStorage.xml
Output
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="authToken">bn_live_7f3a9c21</string>
</map>

The app sandbox stops other apps, not everyone. run-as works on any debuggable build, a rooted phone reads every sandbox, and the Capacitor 243,123 template's manifest sets android:allowBackup="true", so Android's Auto Backup copies shared_prefs/ to the user's cloud backup and device-to-device transfers. On iOS, Preferences is UserDefaults, a plist in the app container that ends up in unencrypted iTunes or Finder backups. The WebView's localStorage and IndexedDB are no better. Use Preferences for settings and the cart; put tokens, passwords and personal data in storage encrypted with a key the operating system guards.