File: securestore.md | Updated: 11/15/2025
Hide navigation
Search
Ctrl K
Home Guides EAS Reference Learn
Reference version
SDK 54 (latest)
Archive Expo Snack Discord and Forums Newsletter
Expo SecureStoreAsk AI
A library that provides a way to encrypt and securely store key-value pairs locally on the device.
Ask AI
Android
iOS
tvOS
Bundled version:
~15.0.7
Copy page
expo-secure-store provides a way to encrypt and securely store key-value pairs locally on the device. Each Expo project has a separate storage system and has no access to the storage of other Expo projects.
Large payloads can be rejected by the underlying platform. Historically, some iOS releases refused values above roughly 2048 bytes. Expo does not enforce a limit, so make sure to handle native errors if you plan to store very large strings.
The requireAuthentication option is not supported in Expo Go when biometric authentication is available due to a missing NSFaceIDUsageDescription key.
Terminal
Copy
-ย npx expo install expo-secure-store
If you are installing this in an existing React Native app
, make sure to install expo
in your project.
You can configure expo-secure-store using its built-in config plugin
if you use config plugins in your project (Continuous Native Generation (CNG)
). The plugin allows you to configure various properties that cannot be set at runtime and require building a new app binary to take effect. If your app does not use CNG, then you'll need to manually configure the library.
app.json
Copy
{ "expo": { "plugins": [ [ "expo-secure-store", { "configureAndroidBackup": true, "faceIDPermission": "Allow $(PRODUCT_NAME) to access your Face ID biometric data." } ] ] } }
| Name | Default | Description |
| --- | --- | --- |
| configureAndroidBackup | true | Only for:โ<br><br>Android<br><br> <br><br>A boolean indicating whether to configure automatic Android backup to work correctly with expo-secure-store. Learn more<br>. |
| faceIDPermission | "Allow $(PRODUCT_NAME) to access your Face ID biometric data." | Only for:โ<br><br>iOS<br><br> <br><br>A string to set the NSFaceIDUsageDescription<br> permission message. |
Are you using this library in an existing React Native app?
Add NSFaceIDUsageDescription key to Info.plist:
Info.plist
Copy
<key>NSFaceIDUsageDescription</key> <string>Allow $(PRODUCT_NAME) to access your Face ID biometric data.</string>
On Android, values are stored in SharedPreferences
, encrypted with Android's Keystore system
.
For iOS standalone apps, data stored with
expo-secure-storecan persist across app installs.
On iOS, values are stored using the keychain services
as kSecClassGenericPassword. iOS has the additional option of being able to set the value's kSecAttrAccessible attribute, which controls when the value is available to be fetched.
expo-secure-store is designed to provide a persistent data storage solution across app restarts and updates. However, it is important not to rely on it as a single source of truth for irreplaceable, critical data. Data saved using expo-secure-store will not be preserved upon app uninstallation. Additionally, any data protected with the requireAuthentication option set to true will become inaccessible if there are changes to the user's biometric settings, such as adding a new fingerprint.
Apple App Store Connect prompts you to select the type of encryption algorithm your app implements. This is known as Export Compliance Information. It is asked when publishing the app or submitting for TestFlight.
When using expo-secure-store, you can set the ios.config.usesNonExemptEncryption
property to false in the app config:
app.json
Copy
{ "expo": { "ios": { "config": { "usesNonExemptEncryption": false } %%placeholder-start%%... %%placeholder-end%% } } }
Setting this property automatically handles the compliance information prompt.
Android Auto Backup for Apps automatically backs up a user's data from apps that target and run on Android 6.0 (API level 23) or higher.
The Auto Backup system has to be configured to exclude expo-secure-store shared preferences entries, as it's impossible to decrypt them after restoring the backup โ app's entries are deleted from the Android Key Store when the app is uninstalled.
If your app doesn't have any custom backup configuration, expo-secure-store will automatically configure the Auto Backup system to ignore the expo-secure-store data.
If you are using your own Auto Backup configuration, you should exclude the SecureStore under the sharedpref domain and set the configureAndroidBackup to false in the config plugin configuration
.
<!-- Auto Backup configuration for Android 12 and higher --> <data-extraction-rules> <cloud-backup> <include domain="sharedpref" path="."/> <exclude domain="sharedpref" path="SecureStore"/> </cloud-backup> <device-transfer> <include domain="sharedpref" path="."/> <exclude domain="sharedpref" path="SecureStore"/> </device-transfer> </data-extraction-rules>
<!-- Auto Backup configuration for Android 11 and lower --> <full-backup-content> <include domain="sharedpref" path="."/> <exclude domain="sharedpref" path="SecureStore"/> </full-backup-content>
SecureStore
Copy
Open in Snack
import { useState } from 'react'; import { Text, View, StyleSheet, TextInput, Button } from 'react-native'; import * as SecureStore from 'expo-secure-store'; async function save(key, value) { await SecureStore.setItemAsync(key, value); } async function getValueFor(key) { let result = await SecureStore.getItemAsync(key); if (result) { alert("๐ Here's your value ๐ \n" + result); } else { alert('No values stored under that key.'); } } export default function App() { const [key, onChangeKey] = useState('Your key here'); const [value, onChangeValue] = useState('Your value here'); return ( <View style={styles.container}> <Text style={styles.paragraph}>Save an item, and grab it later!</Text> {%%placeholder-start%%Add some TextInput components... %%placeholder-end%%} <TextInput style={styles.textInput} clearTextOnFocus onChangeText={text => onChangeKey(text)} value={key} /> <TextInput style={styles.textInput} clearTextOnFocus onChangeText={text => onChangeValue(text)} value={value} /> {} <Button title="Save this key/value pair" onPress={() => { save(key, value); onChangeKey('Your key here'); onChangeValue('Your value here'); }} /> <Text style={styles.paragraph}>๐ Enter your key ๐</Text> <TextInput style={styles.textInput} onSubmitEditing={event => { getValueFor(event.nativeEvent.text); }} placeholder="Enter the key for the value you want to get" /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', paddingTop: 10, backgroundColor: '#ecf0f1', padding: 8, }, paragraph: { marginTop: 34, margin: 24, fontSize: 18, fontWeight: 'bold', textAlign: 'center', }, textInput: { height: 35, borderColor: 'gray', borderWidth: 0.5, padding: 4, }, });
Show More
import * as SecureStore from 'expo-secure-store';
SecureStore.AFTER_FIRST_UNLOCKAndroid
iOS
tvOS
Type: [KeychainAccessibilityConstant](https://docs.expo.dev/versions/latest/sdk/securestore#keychainaccessibilityconstant)
The data in the keychain item cannot be accessed after a restart until the device has been unlocked once by the user. This may be useful if you need to access the item when the phone is locked.
SecureStore.AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLYAndroid
iOS
tvOS
Type: [KeychainAccessibilityConstant](https://docs.expo.dev/versions/latest/sdk/securestore#keychainaccessibilityconstant)
Similar to AFTER_FIRST_UNLOCK, except the entry is not migrated to a new device when restoring from a backup.
Deprecated Use an accessibility level that provides some user protection, such as
AFTER_FIRST_UNLOCK.
SecureStore.ALWAYSAndroid
iOS
tvOS
Type: [KeychainAccessibilityConstant](https://docs.expo.dev/versions/latest/sdk/securestore#keychainaccessibilityconstant)
The data in the keychain item can always be accessed regardless of whether the device is locked. This is the least secure option.
Deprecated Use an accessibility level that provides some user protection, such as
AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY.
SecureStore.ALWAYS_THIS_DEVICE_ONLYAndroid
iOS
tvOS
Type: [KeychainAccessibilityConstant](https://docs.expo.dev/versions/latest/sdk/securestore#keychainaccessibilityconstant)
Similar to ALWAYS, except the entry is not migrated to a new device when restoring from a backup.
SecureStore.WHEN_PASSCODE_SET_THIS_DEVICE_ONLYAndroid
iOS
tvOS
Type: [KeychainAccessibilityConstant](https://docs.expo.dev/versions/latest/sdk/securestore#keychainaccessibilityconstant)
Similar to WHEN_UNLOCKED_THIS_DEVICE_ONLY, except the user must have set a passcode in order to store an entry. If the user removes their passcode, the entry will be deleted.
SecureStore.WHEN_UNLOCKEDAndroid
iOS
tvOS
Type: [KeychainAccessibilityConstant](https://docs.expo.dev/versions/latest/sdk/securestore#keychainaccessibilityconstant)
The data in the keychain item can be accessed only while the device is unlocked by the user.
SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLYAndroid
iOS
tvOS
Type: [KeychainAccessibilityConstant](https://docs.expo.dev/versions/latest/sdk/securestore#keychainaccessibilityconstant)
Similar to WHEN_UNLOCKED, except the entry is not migrated to a new device when restoring from a backup.
SecureStore.canUseBiometricAuthentication()Android
iOS
Checks if the value can be saved with requireAuthentication option enabled.
Returns:
boolean
true if the device supports biometric authentication and the enrolled method is sufficiently secure. Otherwise, returns false. Always returns false on tvOS.
SecureStore.deleteItemAsync(key, options)Android
iOS
tvOS
| Parameter | Type | Description |
| --- | --- | --- |
| key | string | The key that was used to store the associated value. |
| options(optional) | [SecureStoreOptions](https://docs.expo.dev/versions/latest/sdk/securestore#securestoreoptions) | An SecureStoreOptions<br> object.<br><br>Default:{} |
Delete the value associated with the provided key.
Returns:
[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) <void>
A promise that rejects if the value can't be deleted.
SecureStore.getItem(key, options)Android
iOS
tvOS
| Parameter | Type | Description |
| --- | --- | --- |
| key | string | The key that was used to store the associated value. |
| options(optional) | [SecureStoreOptions](https://docs.expo.dev/versions/latest/sdk/securestore#securestoreoptions) | An SecureStoreOptions<br> object.<br><br>Default:{} |
Synchronously reads the stored value associated with the provided key.
Note: This function blocks the JavaScript thread, so the application may not be interactive when reading a value with
requireAuthenticationoption set totrueuntil the user authenticates.
Returns:
string | null
Previously stored value. It resolves with null if there is no entry for the given key or if the key has been invalidated.
SecureStore.getItemAsync(key, options)Android
iOS
tvOS
| Parameter | Type | Description |
| --- | --- | --- |
| key | string | The key that was used to store the associated value. |
| options(optional) | [SecureStoreOptions](https://docs.expo.dev/versions/latest/sdk/securestore#securestoreoptions) | An SecureStoreOptions<br> object.<br><br>Default:{} |
Reads the stored value associated with the provided key.
Returns:
[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) <string | null>
A promise that resolves to the previously stored value. It resolves with null if there is no entry for the given key or if the key has been invalidated. It rejects if an error occurs while retrieving the value.
Keys are invalidated by the system when biometrics change, such as adding a new fingerprint or changing the face profile used for face recognition. After a key has been invalidated, it becomes impossible to read its value. This only applies to values stored with
requireAuthenticationset totrue.
SecureStore.isAvailableAsync()Android
iOS
tvOS
Returns whether the SecureStore API is enabled on the current device. This does not check the app permissions.
Returns:
[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) <boolean>
Promise which fulfils with a boolean, indicating whether the SecureStore API is available on the current device. Currently, this resolves true on Android and iOS only.
SecureStore.setItem(key, value, options)Android
iOS
tvOS
| Parameter | Type | Description |
| --- | --- | --- |
| key | string | The key to associate with the stored value. Keys may contain alphanumeric characters, ., -, and _. |
| value | string | The value to store. |
| options(optional) | [SecureStoreOptions](https://docs.expo.dev/versions/latest/sdk/securestore#securestoreoptions) | An SecureStoreOptions<br> object.<br><br>Default:{} |
Stores a keyโvalue pair synchronously.
Note: This function blocks the JavaScript thread, so the application may not be interactive when the
requireAuthenticationoption is set totrueuntil the user authenticates.
Returns:
void
SecureStore.setItemAsync(key, value, options)Android
iOS
tvOS
| Parameter | Type | Description |
| --- | --- | --- |
| key | string | The key to associate with the stored value. Keys may contain alphanumeric characters, ., -, and _. |
| value | string | The value to store. |
| options(optional) | [SecureStoreOptions](https://docs.expo.dev/versions/latest/sdk/securestore#securestoreoptions) | An SecureStoreOptions<br> object.<br><br>Default:{} |
Stores a keyโvalue pair.
Returns:
[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) <void>
A promise that rejects if value cannot be stored on the device.
KeychainAccessibilityConstantAndroid
iOS
tvOS
Type: number
SecureStoreOptionsAndroid
iOS
tvOS
| Property | Type | Description |
| --- | --- | --- |
| accessGroup(optional) | string | Only for:โ<br><br>iOS<br><br> <br><br>Specifies the access group the stored entry belongs to.<br><br>> See: Apple's documentation on Sharing access to keychain items among a collection of apps<br>> . |
| authenticationPrompt(optional) | string | Custom message displayed to the user while requireAuthentication option is turned on. |
| keychainAccessible(optional) | [KeychainAccessibilityConstant](https://docs.expo.dev/versions/latest/sdk/securestore#keychainaccessibilityconstant) | Only for:โ<br><br>iOS<br><br> <br><br>Specifies when the stored entry is accessible, using iOS's kSecAttrAccessible property.<br><br>Default:SecureStore.WHEN_UNLOCKED<br><br>> See: Apple's documentation on keychain item accessibility<br>> . |
| keychainService(optional) | string | * Android: Equivalent of the public/private key pair Alias.<br>* iOS: The item's service, equivalent to kSecAttrService<br> .<br><br>> If the item is set with the keychainService option, it will be required to later fetch the value. |
| requireAuthentication(optional) | boolean | Option responsible for enabling the usage of the user authentication methods available on the device while accessing data stored in SecureStore.<br><br>* Android: Equivalent to setUserAuthenticationRequired(true)<br> (requires API 23).<br>* iOS: Equivalent to biometryCurrentSet<br> . Complete functionality is unlocked only with a freshly generated key - this would not work in tandem with the keychainService value used for the others non-authenticated operations.<br><br>This option works slightly differently across platforms: On Android, user authentication is required for all operations. On iOS, the user is prompted to authenticate only when reading or updating an existing value (not when creating a new one).<br><br>Warning: This option is not supported in Expo Go when biometric authentication is available due to a missing NSFaceIDUsageDescription. In release builds or when using continuous native generation, make sure to use the expo-secure-store config plugin. |