Everything above sits unencrypted in the app's private directory. That directory is closed to other apps, but not to a rooted phone, a backup tool, or adb shell run-as on a debug build. Tokens, refresh tokens and encryption keys belong in expo-secure-store, which encrypts each value with a key held in the Android Keystore (backed by secure hardware where the phone has it) and stores values in the Keychain on iOS:
import * as SecureStore from 'expo-secure-store';
// Secrets only: encrypted with a key kept in the Android Keystore (iOS: the Keychain)
const KEY = 'booknest.token';
export const saveToken = (token: string) => SecureStore.setItemAsync(KEY, token);
export const readToken = () => SecureStore.getItemAsync(KEY);
export const forgetToken = () => SecureStore.deleteItemAsync(KEY);LOG token read back: demo-token-123
The API is deliberately small: string keys and values, no listing of keys. The benchmark in Local Storage Options Compared shows why it is for secrets only: 40 operations took longer than 1,000 through MMKV 18,748 , since every value is encrypted and decrypted. requireAuthentication: true in the options makes reading a value require the user's biometrics or device credential, and keychainAccessible controls when iOS allows access (for example only after first unlock). Authentication stores BookNest's sign-in token this way.