---
title: SecureStore
description: A library that provides a way to encrypt and securely store key-value pairs locally on the device.
sourceCodeUrl: https://github.com/expo/expo/tree/main/packages/expo-secure-store
packageName: expo-secure-store
iconUrl: /static/images/packages/expo-secure-store.png
platforms: ["android", "ios", "tvos"]
---
import {
ConfigPluginExample,
ConfigReactNative,
ConfigPluginProperties,
} from '~/ui/components/ConfigSection';
`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.
**Size limit for a value is 2048 bytes. An attempt to store larger values may fail. Currently, we print a warning when the limit is reached, however, in a future SDK version an error might be thrown.**
**The `requireAuthentication` option is not supported in Expo Go when biometric authentication is available due to a missing `NSFaceIDUsageDescription` key.**
> This API is not compatible with devices running Android 5 or lower.
## Installation
## Configuration in app config
You can configure `expo-secure-store` using its built-in [config plugin](/config-plugins/introduction/) if you use config plugins in your project ([EAS Build](/build/introduction) or `npx expo run:[android|ios]`). The plugin allows you to configure various properties that cannot be set at runtime and require building a new app binary to take effect.
```json app.json
{
"expo": {
"plugins": [
[
"expo-secure-store",
{
"configureAndroidBackup": true,
"faceIDPermission": "Allow $(PRODUCT_NAME) to access your Face ID biometric data."
}
]
]
}
}
```
Add `NSFaceIDUsageDescription` key to **Info.plist**:
```xml Info.plist
<key>NSFaceIDUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to access your Face ID biometric data.</string>
```
## Platform value storage
### Android
On Android, values are stored in [`SharedPreferences`](https://developer.android.com/training/data-storage/shared-preferences), encrypted with [Android's Keystore system](https://developer.android.com/training/articles/keystore.html).
### iOS
> For iOS standalone apps, data stored with `expo-secure-store` can persist across app installs.
On iOS, values are stored using the [keychain services](https://developer.apple.com/documentation/security/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.
## Data persistence
`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.
#### Exempting encryption prompt
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`](../config/app/#usesnonexemptencryption) property to `false` in the app config:
{/* prettier-ignore */}
```json app.json
{
"expo": {
"ios": {
"config": {
"usesNonExemptEncryption": false
}
/* @hide ... */ /* @end */
}
}
}
```
Setting this property automatically handles the compliance information prompt.
## Android Auto Backup
[Android Auto Backup for Apps](https://developer.android.com/identity/data/autobackup) 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](#example-appjson-with-config-plugin).
```xml
<!-- 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>
```
```xml
<!-- Auto Backup configuration for Android 11 and lower -->
<full-backup-content>
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="SecureStore"/>
</full-backup-content>
```
## Usage
```jsx
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.');
}
}
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>
{/* @hide Add some TextInput components... */}
<TextInput
style={styles.textInput}
clearTextOnFocus
onChangeText={text => onChangeKey(text)}
value={key}
/>
<TextInput
style={styles.textInput}
clearTextOnFocus
onChangeText={text => onChangeValue(text)}
value={value}
/>
{/* @end */}
<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,
},
});
```
## API
```js
```