Skip to main content
Glama
securestore.md7.25 kB
--- 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 &mdash; 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 ```

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jaksm/expo-docs-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server