HomeGuidesReferenceLearn

Reference version

ArchiveExpo SnackDiscord and ForumsNewsletter

Expo SecureStore iconExpo SecureStore

GitHub

npm

A library that provides a way to encrypt and securely store key-value pairs locally on the device.


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.

Platform Compatibility

Android DeviceAndroid EmulatoriOS DeviceiOS SimulatorWeb

This API is not compatible with devices running Android 5 or lower.

Installation

Terminal
npx expo install expo-secure-store

If you're installing this in a bare React Native app, you should also follow these additional installation instructions.

Platform value storage

Android

On Android, values are stored in SharedPreferences, encrypted with Android's Keystore system.

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 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.

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 property to false in the app config:

app.json
{
  "expo": {
    "ios": {
      "config": {
        "usesNonExemptEncryption": false
      }
      %%placeholder-start%%... %%placeholder-end%%
    }
  }
}

Setting this property automatically handles the compliance information prompt.

Usage

SecureStore
import * as React 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] = React.useState('Your key here');
  const [value, onChangeValue] = React.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,
  },
});

API

import * as SecureStore from 'expo-secure-store';

Constants

SecureStore.AFTER_FIRST_UNLOCK

Type: 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_ONLY

Type: KeychainAccessibilityConstant


Similar to AFTER_FIRST_UNLOCK, except the entry is not migrated to a new device when restoring from a backup.

SecureStore.ALWAYS

Type: KeychainAccessibilityConstant


The data in the keychain item can always be accessed regardless of whether the device is locked. This is the least secure option.

SecureStore.ALWAYS_THIS_DEVICE_ONLY

Type: 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_ONLY

Type: 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_UNLOCKED

Type: KeychainAccessibilityConstant


The data in the keychain item can be accessed only while the device is unlocked by the user.

SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY

Type: KeychainAccessibilityConstant


Similar to WHEN_UNLOCKED, except the entry is not migrated to a new device when restoring from a backup.

Methods

SecureStore.deleteItemAsync(key, options)

NameTypeDescription
keystring

The key that was used to store the associated value.

options
(optional)
SecureStoreOptions

An SecureStoreOptions object.

Default: {}

Delete the value associated with the provided key.

Returns

  • Promise<void>

A promise that will reject if the value couldn't be deleted.

SecureStore.getItemAsync(key, options)

NameTypeDescription
keystring

The key that was used to store the associated value.

options
(optional)
SecureStoreOptions

An SecureStoreOptions object.

Default: {}

Fetch the stored value associated with the provided key.

Returns

  • Promise<string | null>

A promise that resolves to the previously stored value, or null if there is no entry for the given key. The promise will reject if an error occurred while retrieving the value.

SecureStore.isAvailableAsync()

Returns whether the SecureStore API is enabled on the current device. This does not check the app permissions.

Returns

  • Promise<boolean>

Promise which fulfils witch boolean, indicating whether the SecureStore API is available on the current device. Currently this resolves true on iOS and Android only.

SecureStore.setItemAsync(key, value, options)

NameTypeDescription
keystring

The key to associate with the stored value. Keys may contain alphanumeric characters ., -, and _.

valuestring

The value to store. Size limit is 2048 bytes.

options
(optional)
SecureStoreOptions

An SecureStoreOptions object.

Default: {}

Store a key–value pair.

Returns

  • Promise<void>

A promise that will reject if value cannot be stored on the device.

Types

KeychainAccessibilityConstant

Type: number

SecureStoreOptions

NameTypeDescription
authenticationPrompt
(optional)
string

Custom message displayed to the user while requireAuthentication option is turned on.

keychainAccessible
(optional)
KeychainAccessibilityConstantOnly for:
iOS

Specifies when the stored entry is accessible, using iOS's kSecAttrAccessible property.

Default: SecureStore.WHEN_UNLOCKED

See: Apple's documentation on keychain item accessibility.

keychainService
(optional)
string
  • iOS: The item's service, equivalent to kSecAttrService
  • Android: Equivalent of the public/private key pair Alias

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.

  • iOS: Equivalent to kSecAccessControlBiometryCurrentSet
  • Android: Equivalent to setUserAuthenticationRequired(true) (requires API 23). 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.