
Security News
Feross on the 10 Minutes or Less Podcast: Nobody Reads the Code
Socket CEO Feross Aboukhadijeh joins 10 Minutes or Less, a podcast by Ali Rohde, to discuss the recent surge in open source supply chain attacks.
@tetherto/wdk-react-native-secure-storage
Advanced tools
Secure storage abstractions for React Native - provides secure storage for sensitive data (encrypted seeds, keys) using react-native-keychain
Secure storage abstractions for React Native - provides secure storage for sensitive data (encrypted seeds, keys) using react-native-keychain.
npm install @tetherto/wdk-react-native-secure-storage
If the package is not yet published to npm, you can install directly from GitHub:
npm install https://github.com/tetherto/wdk-react-native-secure-storage.git
Or add to your package.json:
{
"dependencies": {
"@tetherto/wdk-react-native-secure-storage": "github:tetherto/wdk-react-native-secure-storage"
}
}
Then run npm install.
npm install react-native@">=0.70.0"
import { createSecureStorage } from '@tetherto/wdk-react-native-secure-storage'
// Create storage instance
const storage = createSecureStorage()
// Store encryption key
await storage.setEncryptionKey('my-encryption-key', 'user@example.com')
// Retrieve encryption key
const key = await storage.getEncryptionKey('user@example.com')
if (key) {
console.log('Key retrieved:', key)
}
// Store encrypted seed
await storage.setEncryptedSeed('encrypted-seed-data', 'user@example.com')
// Store encrypted entropy
await storage.setEncryptedEntropy('encrypted-entropy-data', 'user@example.com')
// Get all encrypted data
const allData = await storage.getAllEncrypted('user@example.com')
console.log('All data:', allData)
// Check if wallet exists
const exists = await storage.hasWallet('user@example.com')
// Delete wallet
await storage.deleteWallet('user@example.com')
import { createSecureStorage, defaultLogger, LogLevel } from '@tetherto/wdk-react-native-secure-storage'
// Configure logger
defaultLogger.setLevel(LogLevel.INFO)
// Create storage with custom options
const storage = createSecureStorage({
logger: customLogger, // Optional custom logger
authentication: {
promptMessage: 'Authenticate to access your wallet',
cancelLabel: 'Cancel',
disableDeviceFallback: false,
},
timeoutMs: 30000, // 30 seconds default
})
// Use storage
await storage.setEncryptionKey('key', 'user@example.com')
import {
createSecureStorage,
ValidationError,
KeychainWriteError,
KeychainReadError,
AuthenticationError,
TimeoutError,
} from '@tetherto/wdk-react-native-secure-storage'
const storage = createSecureStorage()
try {
await storage.setEncryptionKey('my-key', 'user@example.com')
} catch (error) {
if (error instanceof ValidationError) {
console.error('Invalid input:', error.message)
} else if (error instanceof KeychainWriteError) {
console.error('Failed to write to keychain:', error.message)
} else if (error instanceof TimeoutError) {
console.error('Operation timed out:', error.message)
} else {
console.error('Unexpected error:', error)
}
}
try {
const key = await storage.getEncryptionKey('user@example.com')
if (!key) {
console.log('Key not found')
}
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Authentication failed:', error.message)
} else if (error instanceof KeychainReadError) {
console.error('Failed to read from keychain:', error.message)
}
}
The identifier parameter allows you to support multiple wallets:
// Store data for different users
await storage.setEncryptionKey('key1', 'user1@example.com')
await storage.setEncryptionKey('key2', 'user2@example.com')
// Retrieve specific user's data
const key1 = await storage.getEncryptionKey('user1@example.com')
const key2 = await storage.getEncryptionKey('user2@example.com')
createSecureStorage(options?)Creates a new instance of secure storage. Each call returns a new instance with the specified options. For most apps, you should create one instance and reuse it throughout your application.
Options:
logger?: Logger - Custom logger instanceauthentication?: AuthenticationOptions - Authentication prompt configurationtimeoutMs?: number - Timeout for keychain operations (default: 30000ms, min: 1000ms, max: 300000ms)Returns: SecureStorage instance
SecureStorage InterfacesetEncryptionKey(key: string, identifier?: string): Promise<void>Stores an encryption key securely.
Parameters:
key: string - The encryption key (max 10KB, non-empty)identifier?: string - Optional identifier for multiple wallets (max 256 chars)Throws:
ValidationError - If input is invalidKeychainWriteError - If keychain operation failsTimeoutError - If operation times outgetEncryptionKey(identifier?: string): Promise<string | null>Retrieves an encryption key.
Parameters:
identifier?: string - Optional identifierReturns: The encryption key or null if not found
Throws:
ValidationError - If identifier is invalidAuthenticationError - If authentication failsKeychainReadError - If keychain operation failsTimeoutError - If operation times outsetEncryptedSeed(encryptedSeed: string, identifier?: string): Promise<void>Stores encrypted seed data.
getEncryptedSeed(identifier?: string): Promise<string | null>Retrieves encrypted seed data.
setEncryptedEntropy(encryptedEntropy: string, identifier?: string): Promise<void>Stores encrypted entropy data.
getEncryptedEntropy(identifier?: string): Promise<string | null>Retrieves encrypted entropy data.
getAllEncrypted(identifier?: string): Promise<{encryptedSeed: string | null, encryptedEntropy: string | null, encryptionKey: string | null}>Retrieves all encrypted wallet data at once.
hasWallet(identifier?: string): Promise<boolean>Checks if wallet credentials exist.
deleteWallet(identifier?: string): Promise<void>Deletes all wallet credentials.
Throws:
ValidationError - If identifier is invalidSecureStorageError - If deletion fails (with details of which items failed)TimeoutError - If operation times outisBiometricAvailable(): Promise<boolean>Checks if biometric authentication is available.
authenticate(): Promise<boolean>Authenticates with biometrics. Returns true if successful, false otherwise.
Throws:
AuthenticationError - If authentication failsThe module provides a Logger interface for structured logging. The default logger can be configured:
import { defaultLogger, LogLevel } from '@tetherto/wdk-react-native-secure-storage'
// Set the minimum log level (logs below this level will be ignored)
defaultLogger.setLevel(LogLevel.INFO)
// Available log levels: DEBUG, INFO, WARN, ERROR
You can also provide a custom logger that implements the Logger interface:
const customLogger: Logger = {
debug: (message, context) => { /* ... */ },
info: (message, context) => { /* ... */ },
warn: (message, context) => { /* ... */ },
error: (message, error, context) => { /* ... */ },
setLevel: (level) => { /* optional */ },
}
const storage = createSecureStorage({ logger: customLogger })
The module has no shared state or cleanup requirements. Each storage instance is independent and can be used without any module-level lifecycle management.
SecureStorageError - Base error classKeychainError - Keychain operation errorsKeychainWriteError - Keychain write failuresKeychainReadError - Keychain read failuresAuthenticationError - Authentication failuresValidationError - Input validation failuresTimeoutError - Operation timeout errors# Run tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:coverage
# Type checking
npm run typecheck
# Linting
npm run lint
npm run lint:fix
# Formatting
npm run format
npm run format:check
Note: ESLint and Prettier are configured but need to be installed as dev dependencies:
npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin prettier
This module is production-ready and includes:
✅ Built and tested - All code is compiled to JavaScript with TypeScript definitions
✅ Proper exports - Only necessary files are included in the npm package
✅ Security hardened - Input validation and secure storage with device-level protections
✅ Error handling - Comprehensive error types for all failure scenarios
✅ Logging - Structured logging with configurable levels (defaults to ERROR in production)
✅ Type safety - Full TypeScript support with exported types
✅ Documentation - Complete API documentation and usage examples
Configure Logging: Set appropriate log levels for your environment:
import { defaultLogger, LogLevel } from '@tetherto/wdk-react-native-secure-storage'
// In production, only log errors and warnings
defaultLogger.setLevel(LogLevel.WARN)
// In development, you might want more verbose logging
if (__DEV__) {
defaultLogger.setLevel(LogLevel.DEBUG)
}
Error Handling: Always handle errors appropriately:
try {
await storage.setEncryptionKey(key, identifier)
} catch (error) {
// Log error to your error tracking service (e.g., Sentry)
// Never log sensitive data like keys or seeds
if (error instanceof ValidationError) {
// Handle validation errors
} else if (error instanceof KeychainWriteError) {
// Handle keychain errors
}
}
Single Instance: Create one storage instance and reuse it:
// Good: Create once and reuse
const storage = createSecureStorage({ logger: customLogger })
// Avoid: Creating multiple instances unnecessarily
⚠️ Important Security Notes:
Timeout Resource Usage: The timeout implementation uses Promise.race() which does NOT cancel the underlying keychain operation. The operation continues executing even after timeout, though its result is ignored. This means:
Device Authentication: On devices without authentication (no PIN/password/biometrics), data is still encrypted at rest but accessible when the device is unlocked. This is a limitation of the underlying platform security model.
Device-Level Rate Limiting: The module relies on device-level keychain/keystore rate limiting and lockout mechanisms. These are more robust than app-level rate limiting and persist across app restarts.
Contributions are welcome! Please follow these steps:
git checkout -b feature/amazing-feature)npm test)npm run typecheck)npm run lint)npm run format)npm run build)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)# Clone the repository
git clone https://github.com/tetherto/wdk-react-native-secure-storage.git
cd wdk-react-native-secure-storage
# Install dependencies
npm install
# Run tests
npm test
# Run type checking
npm run typecheck
# Run linting
npm run lint
# Format code
npm run format
# Build
npm run build
Apache-2.0
FAQs
Secure storage abstractions for React Native - provides secure storage for sensitive data (encrypted seeds, keys) using react-native-keychain
We found that @tetherto/wdk-react-native-secure-storage demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket CEO Feross Aboukhadijeh joins 10 Minutes or Less, a podcast by Ali Rohde, to discuss the recent surge in open source supply chain attacks.

Research
/Security News
Campaign of 108 extensions harvests identities, steals sessions, and adds backdoors to browsers, all tied to the same C2 infrastructure.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.