One.ProtectedStore keeps a separate protected namespace for secrets that
require device authentication. It uses Keychain on iOS and per-item Android
Keystore keys with encrypted records on Android 11 (API 30) or later. Unlike One.SecureStore,
every item has an access control policy. All calls are asynchronous so a system
authentication prompt does not block the JavaScript thread.
import { One } from 'one'
await One.ProtectedStore.createItem('recovery-key', secret, 'biometryCurrentSet')const value = await One.ProtectedStore.getItem( 'recovery-key', 'Unlock your recovery key', 'biometryCurrentSet')await One.ProtectedStore.updateItem('recovery-key', nextSecret, 'Update your recovery key', 'biometryCurrentSet')await One.ProtectedStore.deleteItem('recovery-key', 'Remove your recovery key', 'biometryCurrentSet')Set native.app.ios.faceIdUsageDescription before prebuilding, including for
apps that also support Touch ID. One’s Android library manifest declares the normal install-time permission
android.permission.USE_BIOMETRIC; Android’s manifest merger adds it to the app.
If the app explicitly removes that permission, calls reject
E_PROTECTED_STORE_MANIFEST. The system displays the supplied reason when
it asks the user to authenticate.
userPresence accepts biometrics or the device passcode. biometryCurrentSet
requires the currently enrolled biometrics and invalidates the item when that
enrollment changes. Both policies keep the item on this device and make it
available only while unlocked. The policy is fixed when createItem succeeds;
pass the same policy to later reads and mutations. updateItem changes the value
while keeping that policy. A mismatched policy on a read or update rejects with
E_PROTECTED_STORE_POLICY. createItem rejects
with E_PROTECTED_STORE_EXISTS if the key already exists. Delete it first to
create a new item with another policy.
getItem returns null for a missing item. An item invalidated by a biometric
enrollment change cannot be read; deleteItem can remove it so its key can be
reused. updateItem rejects
with E_PROTECTED_STORE_NOT_FOUND for a missing key. deleteItem succeeds for a
missing key. A canceled prompt rejects with E_PROTECTED_STORE_CANCELLED;
authentication failures use E_PROTECTED_STORE_AUTH. Invalid keys or reasons
use E_PROTECTED_STORE_INPUT; missing Face ID purpose text uses
E_PROTECTED_STORE_MANIFEST. Other Keychain errors use
E_PROTECTED_STORE_GET or E_PROTECTED_STORE_WRITE.
On Android, creation needs no authentication prompt. Every read or update
authenticates one fresh private-key operation, and every existing-item deletion
requires fresh authentication. Existing calls made while the device is locked
reject with E_PROTECTED_STORE_AUTH without presenting a prompt or changing
the item. Missing results apply only when both the encrypted record and its
Keystore alias are absent. An interrupted creation can leave an occupied alias;
explicit deletion authenticates its immutable policy before removing it.
Values and temporary encryption keys are never stored as plaintext.
Web and Android versions below API 30 remain unavailable; they never read or
write an unprotected substitute. Other Android storage and cipher errors use
E_PROTECTED_STORE_GET or E_PROTECTED_STORE_WRITE. See Apple’s
Keychain access control guide
for the underlying policy behavior.
Android uses Keystore access controls and BiometricPrompt CryptoObject for authentication per private operation.
Edit this page on GitHub.