Working with Secure Storage (expo-secure-store)
1. Storing Secure Data
| Property | Description | Notes |
|---|---|---|
| setItemAsync(key, value, options) | Stores a value securely under the given key | Values are encrypted and stored in secure storage |
| setItemAsync(key, value, options) | Stores a value securely under the given key | Values are encrypted and stored in secure storage |
Example: Storing a Token
import * as SecureStore from 'expo-secure-store';
await SecureStore.setItemAsync('authToken', 'abc123xyz');
Note: SecureStore uses platform-specific secure storage (Keychain on iOS, Keystore on Android).
2. Retrieving Secure Data
| Method | Description | Return Type | Notes |
|---|---|---|---|
| SecureStore.getItemAsync(key) | Retrieves a value for the given key | Promise<string | null> |
Resolves to the stored value or null if not found |
| SecureStore.getItemAsync(key, options) | Retrieves a value for the given key with additional options | Promise<string | null> |
Supports keychainService and accessControl options |
Example: Retrieving Secure Data
import * as SecureStore from 'expo-secure-store';
const token = await SecureStore.getItemAsync('authToken');
if (token) {
console.log('Retrieved token:', token);
} else {
console.log('No token found');
}
Note: On Android,
getItemAsync will return null if the key is not found, and on iOS it will throw an error if the key does not exist.
3. Deleting Secure Data
| Method | Description | Notes |
|---|---|---|
| deleteItemAsync(key) | Deletes the value associated with the given key. | Returns a Promise that resolves when deletion is complete. |
| deleteItemAsync(key, options) | Deletes the value associated with the given key using specified options. | Supports secure storage options like keychainService. |
Example: Deleting Secure Data
import * as SecureStore from 'expo-secure-store';
await SecureStore.deleteItemAsync('userToken');
console.log('Token deleted successfully');
Note: If the key does not exist,
deleteItemAsync will resolve without error.
4. Setting Storage Options
| Option | Values | Description |
|---|---|---|
| keychainService | string |
Custom keychain service name for iOS. Defaults to app bundle ID. |
| keychainAccessGroup | string |
Keychain access group for iOS. Allows sharing between apps. |
| sharedPreferencesName | string |
Shared preferences name for Android. Defaults to app package name. |
| encryptionKey | string |
Custom encryption key for Android. If not provided, uses default. |
Example: Setting Custom Keychain Service
import * as SecureStore from 'expo-secure-store';
await SecureStore.setAsync("key", "value", {
keychainService: "com.myapp.custom-service"
});
Example: Setting Shared Preferences Name
import * as SecureStore from 'expo-secure-store';
await SecureStore.setAsync("key", "value", {
sharedPreferencesName: "com.myapp.shared-prefs"
});
5. Configuring Keychain Access
Example: Basic Keychain Configuration
import * as SecureStore from 'expo-secure-store';
const key = 'my-secure-key';
const value = 'sensitive-data';
await SecureStore.setItemAsync(key, value);
const retrieved = await SecureStore.getItemAsync(key);
console.log(retrieved); // "sensitive-data"
| Configuration Option | Description | Default Value |
|---|---|---|
| keychainService | Custom keychain service name for iOS | expo-secure-store |
| keychainAccessGroup | Keychain access group for iOS (requires entitlements) | null |
Note: On iOS,
keychainAccessGroup requires the com.apple.developer.keychain-access-groups entitlement to be set in your app's Info.plist.
Warning: On Android,
keychainAccessGroup is not supported and will be ignored.
6. Using Device Authentication
Example: Secure Storage with Biometric Authentication
import * as SecureStore from 'expo-secure-store';
const KEY = 'user_token';
// Store token with biometric lock
await SecureStore.setItemAsync(KEY, token, {
keychainAccess: 'biometry',
});
// Retrieve token (requires biometric authentication)
const storedToken = await SecureStore.getItemAsync(KEY, {
keychainAccess: 'biometry',
});
| Option | Values | Description |
|---|---|---|
| keychainAccess | 'biometry', 'devicePasscode', 'always' |
Controls how the keychain item is secured |
| keychainAccess | 'never' |
Item is not secured with biometrics or passcode |
Note:
'biometry' requires the device to have biometric hardware (fingerprint, face ID) and the user to have enrolled biometrics.
Warning: If the user removes their biometric data (e.g., deletes fingerprints), the stored items become inaccessible and must be re-registered.
7. Checking Availability
| Method | Description | Return Type | Notes |
|---|---|---|---|
| SecureStore.isAvailableAsync() | Checks if secure storage is available on the device | Promise<boolean> |
Returns true if secure storage is accessible, false otherwise |
Example: Checking Secure Store Availability
import * as SecureStore from 'expo-secure-store';
async function checkSecureStoreAvailability() {
const isAvailable = await SecureStore.isAvailableAsync();
if (isAvailable) {
console.log('Secure storage is available');
} else {
console.log('Secure storage is not available on this device');
}
}
checkSecureStoreAvailability();
8. Storing Credentials
Example: Storing and Retrieving Credentials
import * as SecureStore from 'expo-secure-store';
const storeCredentials = async () => {
await SecureStore.setItemAsync('authToken', 'abc123xyz');
await SecureStore.setItemAsync('refreshToken', 'def456uvw');
};
const getCredentials = async () => {
const token = await SecureStore.getItemAsync('authToken');
const refreshToken = await SecureStore.getItemAsync('refreshToken');
return { token, refreshToken };
};
storeCredentials();
getCredentials().then(creds => console.log(creds));
| Method | Description | Notes |
|---|---|---|
| setItemAsync(key, value) | Stores a key-value pair securely | Overwrites existing values |
| getItemAsync(key) | Retrieves the value for a given key | Returns null if key doesn't exist |
| deleteItemAsync(key) | Deletes a key-value pair | Does not throw if key doesn't exist |
| clearAsync() | Deletes all stored items | Use with caution |
Note: Values are stored encrypted and are only accessible to your app.
Warning: Do not store sensitive data like passwords in plain text or unencrypted formats.
9. Handling Storage Errors
Example: Error Handling with Expo Secure Store
import * as SecureStore from 'expo-secure-store';
async function secureStorageWithErrors() {
try {
await SecureStore.setItemAsync('userToken', 'abc123xyz');
const token = await SecureStore.getItemAsync('userToken');
console.log('Token retrieved:', token);
} catch (error) {
console.error('Secure Store Error:', error.message);
// Handle specific error types
if (error.name === 'SecureStoreError') {
// Log or report error
console.error('Secure Store operation failed');
}
}
}
| Error Type | Description | Handling Recommendation |
|---|---|---|
| SecureStoreError | Generic error thrown by SecureStore operations | Log the error and provide user feedback or retry logic |
| SecurityError | Occurs when storage is compromised or locked (e.g., device passcode removed) | Clear sensitive data and prompt user to re-authenticate or reset |
| PermissionError | Thrown when app lacks required permissions (rare in Expo) | Inform user to check app permissions or reinstall |
Note: On some Android devices, SecureStore may throw errors if the device is not properly secured (e.g., no lock screen). Always wrap operations in try/catch blocks.
10. Using Biometric Protection
| Property | Description | Values |
|---|---|---|
| biometricAuth | Enables biometric authentication for secure storage access | true or false |
| requireAuthentication | Specifies whether authentication is required before accessing stored data | true or false |
| authenticationPrompt | Custom message displayed to the user during biometric authentication | string |
Example: Setting up biometric protection
import * as SecureStore from 'expo-secure-store';
await SecureStore.setItemAsync(
'userToken',
'abc123',
{
biometricAuth: true,
requireAuthentication: true,
authenticationPrompt: 'Authenticate to access your token'
}
);
Note: Biometric authentication is only available on devices that support it (e.g., iOS devices with Face ID or Touch ID, Android devices with fingerprint readers).