A comprehensive, cross-platform React Native wrapper for secure key-value storage using native security features of Android and iOS. It supports **biometric authentication**, **hardware-backed encryption**, and deep platform integrations such as **Android
npm install rn-secure-keystoreA comprehensive, cross-platform React Native wrapper for secure key-value storage using native security features of Android and iOS. It supports biometric authentication, hardware-backed encryption, and deep platform integrations such as Android StrongBox, EncryptedSharedPreferences, and iOS Secure Enclave via the Keychain.
This library enables storing data securely with biometric protection, ensuring that sensitive information can only be accessed after successful biometric verification (e.g., fingerprint or face recognition). This adds an additional layer of security by requiring user authentication to retrieve or modify protected data, making it ideal for handling highly sensitive data.
- Hardware-backed security – Utilizes device secure elements when available
- Biometric authentication – Store and retrieve data with biometric protection
- Cross-platform – Works on both iOS and Android with platform-specific optimizations
- StrongBox support _(Android only)_ – Enhanced protection using dedicated security chips
- iOS Keychain integration – Access to iOS Keychain access controls
- Secure storage – Store sensitive data like tokens, passwords, and user credentials
- Error handling – Comprehensive error codes and recovery mechanisms
- Security introspection – Check security levels and platform capabilities
- Fallback mechanisms – Graceful degradation when advanced features aren't available
``bash`
npm install rn-secure-keystore
`bash`
cd ios && pod install
Add the following to your Info.plist:
`xml`
Ensure your android/app/build.gradle has minimum SDK version 23:
`gradle`
android {
compileSdkVersion 34
defaultConfig {
minSdkVersion 23
// ...
}
}
Add biometric permissions to android/app/src/main/AndroidManifest.xml:
`xml`
> Note: This library requires native modules and will not work with Expo Go.
On iOS, all data is securely stored using the native Keychain. For devices with Secure Enclave (iPhone 5s and later), encryption is hardware-backed, meaning your secrets are tied to the physical chip and are secure.
Key benefits:
- Secure Enclave for hardware-backed storage
- Support for access groups and keychain sharing between apps
- Advanced access control options
- Hardware backing when available
#### EncryptedSharedPreferences
This library uses Android Jetpack's EncryptedSharedPreferences with fallback to regular SharedPreferences, which combines:
- A master key stored in Android's Keystore
- AES encryption for your key-value pairs
- Automatic key generation and rotation
- Graceful fallback for compatibility
#### StrongBox
On supported devices (API 28+), you can optionally store encryption keys in StrongBox, a hardware security module (HSM) separate from the main CPU. This provides maximum protection, especially against physical tampering.
- Resistant to rooting and debugging
- Keys stored in StrongBox are non-exportable
- Enforced user authentication (e.g., biometrics) via hardware-backed checks
- Fallback to TEE (Trusted Execution Environment) if StrongBox is unavailable
> StrongBox is only available on select newer Android devices with a dedicated secure element (Pixel 3+, Samsung S9+, etc.).
| Level | Description | Use Case |
| ----------- | -------------------------------------------------------- | -------------------- |
| strongbox | Stored in StrongBox HSM; maximum protection if available | Ultra-sensitive data |hardware
| | Backed by Trusted Execution Environment (TEE) | Sensitive data |software
| | Software-encrypted; fallback for older devices | Basic protection |auto
| | Automatically chooses the strongest supported level | Recommended default |
- iOS Keychain automatically uses hardware-backed encryption when the device supports Secure Enclave
- Hardware backing is transparent and automatic on supported iOS devices
`typescript
import SecureStorage from 'rn-secure-keystore';
// Store a value
await SecureStorage.setItem('userToken', 'abc123');
// Retrieve a value
const token = await SecureStorage.getItem('userToken');
// Check if a key exists
const exists = await SecureStorage.hasItem('userToken');
// Remove a value
await SecureStorage.removeItem('userToken');
// Get all keys
const keys = await SecureStorage.getAllKeys();
// Clear all data
await SecureStorage.clear();
`
`typescript
// Store with biometric protection
await SecureStorage.setItem('sensitiveData', 'secret', {
withBiometric: true,
authenticatePrompt: 'Authenticate to store sensitive data',
authenticatePromptSubtitle:
'Use your fingerprint or face to secure this data',
});
// Retrieve with biometric authentication
const data = await SecureStorage.getItem('sensitiveData', {
authenticatePrompt: 'Authenticate to access sensitive data',
authenticatePromptSubtitle: 'Use your biometric to continue',
});
`
`typescript
// Check device capabilities
const capabilities = await SecureStorage.getPlatformCapabilities();
console.log('StrongBox available:', capabilities.hasStrongBox);
// Store with specific security level
await SecureStorage.setItem('data', 'value', {
securityLevel: 'strongbox', // 'strongbox' | 'hardware' | 'software' | 'auto'
allowFallback: true, // Allow fallback if StrongBox not available
});
// Use convenience method for StrongBox
await SecureStorage.setStrongBoxItem('ultraSecure', 'data', true);
// Get recommended security level
const recommendedLevel = await SecureStorage.getRecommendedSecurityLevel();
`
`typescript
import SecureStorage, { ACCESS_CONTROL } from 'rn-secure-keystore';
// Store with specific access control (no biometric required for basic storage)
await SecureStorage.setItem('basicData', 'value');
// Store with biometric requirement
await SecureStorage.setItem('biometricData', 'secret', {
accessControl: ACCESS_CONTROL.BIOMETRY_ANY_OR_DEVICE_PASSCODE,
authenticatePrompt: 'Authenticate to store data',
});
// Use convenience method
await SecureStorage.setKeychainItem(
'keychainData',
'secret',
ACCESS_CONTROL.BIOMETRY_CURRENT_SET,
'com.yourapp.shared' // access group (optional)
);
`
`typescript
// Check individual key security
const isHardwareBacked = await SecureStorage.isKeyHardwareBacked('myKey');
const securityLevel = await SecureStorage.getKeySecurityLevel('myKey');
// Get security status for all keys
const securityStatus = await SecureStorage.getSecurityStatus();
console.log('All keys security:', securityStatus);
// Check if device meets requirements
const requirements = {
requireBiometric: true,
requireHardwareBacking: true,
requireStrongBox: false,
};
const { meets, missing } =
await SecureStorage.meetsSecurityRequirements(requirements);
`
#### setItem(key: string, value: string, options?: StorageOptions): Promise
Stores a key-value pair securely with optional biometric protection and security level specification.
Parameters:
- key: Unique identifier for the stored valuevalue
- : Data to store securelyoptions
- : Optional configuration object
Example:
`typescript`
await SecureStorage.setItem('apiKey', 'sk-123456', {
withBiometric: true,
securityLevel: 'hardware', // Android only
accessControl: ACCESS_CONTROL.BIOMETRY_ANY, // iOS only
});
#### getItem(key: string, options?: GetItemOptions): Promise
Retrieves a stored value, prompting for authentication if required.
#### removeItem(key: string): Promise
Removes a stored key-value pair from secure storage.
#### hasItem(key: string): Promise
Checks if a key exists in storage without retrieving the value.
#### getAllKeys(): Promise
Returns an array of all stored keys.
#### clear(): Promise
Clears all secure storage and removes all encryption keys.
#### isBiometricAvailable(): Promise
Checks if biometric authentication is available and enrolled on the device.
#### isHardwareBackedAvailable(): Promise
Checks if hardware-backed keystore is available on the current device.
#### isStrongBoxAvailable(): Promise
Checks if StrongBox hardware security module is available (Android only).
#### getHardwareSecurityInfo(): Promise
Returns comprehensive information about device security capabilities.
`typescript`
const info = await SecureStorage.getHardwareSecurityInfo();
// {
// isHardwareBackedAvailable: true,
// isStrongBoxAvailable: true,
// recommendedSecurityLevel: 'strongbox'
// }
#### getPlatformCapabilities(): Promise
Returns detailed platform-specific feature availability.
#### isKeyHardwareBacked(key: string): Promise
Checks if a specific stored key uses hardware-backed security.
#### getKeySecurityLevel(key: string): Promise
Returns the security level of a specific key ('strongbox', 'hardware', 'software', 'unknown').
#### getRecommendedSecurityLevel(): Promise<'strongbox' | 'hardware' | 'software'>
Returns the recommended security level for the current device.
#### getSecurityStatus(): Promise
Returns security information for all stored keys.
#### meetsSecurityRequirements(requirements): Promise<{meets: boolean, missing: string[]}>
Checks if the current device meets specified security requirements.
#### Android Only
##### setStrongBoxItem(key: string, value: string, allowFallback?: boolean): Promise
Convenience method to store data with StrongBox security.
#### iOS Only
##### setKeychainItem(key: string, value: string, accessControl?: string, accessGroup?: string): Promise
Convenience method for iOS Keychain with custom access control.
#### migrateToSecureStorage(key: string, plainValue: string, options?: StorageOptions): Promise
Migrates plain text data to secure storage.
#### isSecurityLevelAvailable(level: 'strongbox' | 'hardware'): Promise
Checks if a specific security level is available on the current device.
`typescript`
interface StorageOptions {
withBiometric?: boolean;
// Android-specific options
requireStrongBox?: boolean;
requireHardware?: boolean;
securityLevel?: 'auto' | 'strongbox' | 'hardware' | 'software';
allowFallback?: boolean;
// iOS-specific options
accessGroup?: string | null;
accessControl?: string | null;
// Authentication prompts
authenticatePrompt?: string;
authenticatePromptSubtitle?: string;
}
`typescript`
interface GetItemOptions {
// iOS-specific
accessGroup?: string | null;
kLocalizedFallbackTitle?: string;
// Android-specific
showModal?: boolean;
// Common
authenticatePrompt?: string;
authenticatePromptSubtitle?: string;
}
`typescript`
interface HardwareSecurityInfo {
isHardwareBackedAvailable: boolean;
isStrongBoxAvailable: boolean;
recommendedSecurityLevel: 'strongbox' | 'hardware' | 'software';
}
`typescript`
interface PlatformCapabilities {
platform: string;
hasStrongBox: boolean;
hasHardwareBackedKeystore: boolean;
hasBiometrics: boolean;
hasKeychainAccessControl: boolean;
}
`typescript
import { ACCESS_CONTROL } from 'rn-secure-keystore';
const ACCESS_CONTROL = {
BIOMETRY_ANY: 'kSecAccessControlBiometryAny',
BIOMETRY_CURRENT_SET: 'kSecAccessControlBiometryCurrentSet',
DEVICE_PASSCODE: 'kSecAccessControlDevicePasscode',
APPLICATION_PASSWORD: 'kSecAccessControlApplicationPassword',
BIOMETRY_ANY_OR_DEVICE_PASSCODE:
'kSecAccessControlBiometryAnyOrDevicePasscode',
};
`
`typescript
import { ERROR_CODES } from 'rn-secure-keystore';
// Authentication errors
ERROR_CODES.AUTHENTICATION_CANCELLED;
ERROR_CODES.AUTHENTICATION_FAILED;
ERROR_CODES.BIOMETRIC_NOT_AVAILABLE;
// Platform errors
ERROR_CODES.PLATFORM_NOT_SUPPORTED;
ERROR_CODES.STRONGBOX_NOT_AVAILABLE;
// Storage errors
ERROR_CODES.STORAGE_ERROR;
ERROR_CODES.RETRIEVAL_ERROR;
// ... and more
`
The library provides comprehensive error handling with detailed error codes:
`typescript
import { SecureStorageError, ERROR_CODES } from 'rn-secure-keystore';
try {
await SecureStorage.getItem('protectedKey');
} catch (error) {
if (error instanceof SecureStorageError) {
switch (error.code) {
case ERROR_CODES.AUTHENTICATION_CANCELLED:
console.log('User cancelled authentication');
break;
case ERROR_CODES.BIOMETRIC_NOT_AVAILABLE:
console.log('Biometric authentication not available');
break;
case ERROR_CODES.STRONGBOX_NOT_AVAILABLE:
console.log('StrongBox not supported on this device');
break;
default:
console.error('Storage error:', error.message);
}
}
}
`
`typescript`
const capabilities = await SecureStorage.getPlatformCapabilities();
if (capabilities.hasStrongBox) {
// Use StrongBox for maximum security
await SecureStorage.setStrongBoxItem('ultraSecret', 'value');
} else if (capabilities.hasHardwareBackedKeystore) {
// Fallback to hardware backing
await SecureStorage.setItem('secret', 'value', { securityLevel: 'hardware' });
}
`typescript`
const biometricAvailable = await SecureStorage.isBiometricAvailable();
if (biometricAvailable) {
await SecureStorage.setItem('biometricData', 'secret', {
withBiometric: true,
});
} else {
// Fallback to device passcode or other authentication
await SecureStorage.setItem('data', 'secret');
}
`typescript
// For highly sensitive data (credit cards, private keys)
await SecureStorage.setItem('creditCard', cardNumber, {
securityLevel: 'strongbox',
withBiometric: true,
allowFallback: true,
});
// For moderately sensitive data (API tokens)
await SecureStorage.setItem('apiToken', token, {
securityLevel: 'hardware',
allowFallback: true,
});
// For less sensitive data (user preferences)
await SecureStorage.setItem('userPrefs', preferences);
`
`typescript`
try {
const secret = await SecureStorage.getItem('protectedData', {
authenticatePrompt: 'Access your secure data',
});
} catch (error) {
if (error instanceof SecureStorageError) {
switch (error.code) {
case ERROR_CODES.AUTHENTICATION_CANCELLED:
// Don't show error, user intentionally cancelled
break;
case ERROR_CODES.AUTHENTICATION_FAILED:
showRetryDialog();
break;
default:
showGenericErrorDialog(error.message);
}
}
}
`typescript${key}: Hardware=${info.isHardwareBacked}, Level=${info.securityLevel}
const securityStatus = await SecureStorage.getSecurityStatus();
for (const [key, info] of Object.entries(securityStatus)) {
console.log(
`
);
}
| Feature | iOS | Android | Notes |
| ----------------- | ------------------------ | ------------------------ | ------------------------------------------------ |
| Basic Storage | Hardware-backed keychain | Default Android Keystore | iOS automatically hardware-backed when available |
| Hardware Storage | Same as basic | Explicit TEE backing | iOS: automatic, Android: explicit |
| StrongBox | Not available | Dedicated security chip | Android-only feature |
| Biometric Storage | Face ID/Touch ID | Fingerprint | Platform-native biometric APIs |
iOS:
- Basic storage = Hardware storage (automatically hardware-backed)
- Access control determines authentication requirements
- All keychain items are secure when Secure Enclave is available
Android:
- Hardware ≠ StrongBox (explicit security levels)
- Manual security level control
- StrongBox provides highest security when available
#### "The package doesn't seem to be linked"
- Run npx pod-install (iOS)
- Rebuild your app after installation
- Avoid Expo Go (use development build)
#### Multiple biometric prompts
- Use single setItem() call with withBiometric: truegetItem()
- Don't call immediately after setItem() for biometric-protected data
#### "bad base-64" error (Android)
- Corrupted EncryptedSharedPreferences data
- Use clear() method to clean up corrupted storage
- Library automatically handles fallback to regular SharedPreferences
#### StrongBox not available
- StrongBox requires newer Android devices (API 28+)
- Use allowFallback: true for broader compatibilityisStrongBoxAvailable()
- Check before using
#### Authentication errors
- Ensure biometrics are enrolled on device
- Use clear authenticatePrompt messages
- Handle user cancellations gracefully
Enable logging to see detailed storage operations:
`typescript
// Check device capabilities
const info = await SecureStorage.getHardwareSecurityInfo();
console.log('Security capabilities:', info);
// Check individual key security
const keyInfo = await SecureStorage.isKeyHardwareBacked('myKey');
console.log('Key hardware-backed:', keyInfo);
`
- React Native: 0.60+
- iOS: 11.0+
- Android: API level 23+ (Android 6.0+)
`typescript
const requirements = {
requireBiometric: true,
requireHardwareBacking: true,
requireStrongBox: false,
};
const { meets, missing } =
await SecureStorage.meetsSecurityRequirements(requirements);
if (!meets) {
console.log('Missing security features:', missing);
}
`
`typescript`
// Migrate existing plain text data to secure storage
await SecureStorage.migrateToSecureStorage('oldKey', plainTextValue, {
securityLevel: 'hardware',
withBiometric: true,
});
MIT
Contributions are welcome! Please open issues and pull requests with clear descriptions.
For issues and questions:
- GitHub Issues: Report bugs and feature requests
- Documentation: Check this README for comprehensive API documentation
- Examples: See the /example` folder for complete usage examples
---
Made with ❤️ for React Native developers who care about security.