One Logo Pool Ball
wwwwwwwwwwwwwwwwwww

SecureStore

Secure string storage backed by the Keychain and Android Keystore

String key-value storage through One.SecureStore. Backed by the Keychain on iOS and AES-256-GCM ciphertexts under a key in Android Keystore on Android.

import { One } from 'one'
await One.SecureStore.setItem('token', 'abc')
const token = await One.SecureStore.getItem('token')
// 'abc', or null when the key holds nothing
await One.SecureStore.deleteItem('token')

getItemSync, setItemSync, and deleteItemSync do the same work synchronously, blocking the JS thread on the Keychain or Keystore the way expo-secure-store’s getItem and setItem do. Use them for a value the first render needs, such as a saved session token:

const token = One.SecureStore.getItemSync('token')

Both forms read and write the same items. Keys are non-empty strings and values are strings; anything else throws at the JS boundary. A missing key reads null, and deleting one resolves all the same. iOS items are readable while the device is unlocked. Android writes commit to disk before resolving, so a relaunch right after a set still reads the value; only runtime failures reject (the sync verbs throw), with E_SECURE_STORE_GET, E_SECURE_STORE_SET, or E_SECURE_STORE_DELETE.

There are no options: no access groups, no accessibility levels, no shared-preferences name. For secrets that require Face ID, Touch ID, or the device passcode on iOS, use Protected Store. On web every verb rejects, or throws for the sync verbs, with SecureStore.<verb> needs an iOS or Android build, since anything kept in localStorage would persist in cleartext.

One-generated apps set android:allowBackup="false" (from the community template), so stored values are never backed up. If an app opts into backup, the preferences file restores without the Keystore key, which never leaves the device, and restored values fail to decrypt: reads reject with E_SECURE_STORE_GET until the value is rewritten.

Edit this page on GitHub.