vault_storage 2.1.2 copy "vault_storage: ^2.1.2" to clipboard
vault_storage: ^2.1.2 copied to clipboard

A package for secure key-value and file storage using Hive and flutter_secure_storage.

Vault Storage #

A secure, fast, and simple local storage solution for Flutter. Built on Hive and Flutter Secure Storage with AES-GCM encryption. Provides key-value storage and encrypted file storage with full web compatibility. Heavy crypto/JSON/base64 work runs in background isolates to keep your UI smooth.

Features #

  • Simple API: Intuitive methods with clear intent (saveSecure/saveNormal/get/delete/clear…)
  • Smart lookups: get() checks normal first, then secure for performance, or constrain via isSecure
  • List stored keys: keys() returns existing keys (optionally filter secure/normal and include file keys)
  • Encrypted file storage: Secure (AES-GCM 256-bit) and normal file storage, unified API across platforms
  • Web compatible: Native file system on devices; web stores bytes in Hive and auto-downloads on retrieval
  • Fast by default: Crypto, JSON (large), and base64 (large) are offloaded to isolates
  • Large-file streaming: Secure file encryption supports chunked streaming to reduce memory pressure
  • Configurable performance: Tweak isolate thresholds via VaultStorageConfig
  • Framework agnostic: Works with any state management or none

Use Cases #

πŸš€ Built for apps that actually matter. Whether you're building the next unicorn or just want your users' data to be safe, Vault Storage has you covered:

πŸ₯ Healthcare & Medical Apps #

  • Patient Records: Keep medical data secure and HIPAA-compliant out of the box
  • Medical Imaging: Store diagnostic images offline without compromising security
  • Health Tracking: Protect sensitive health data with enterprise-grade encryption

🏦 Financial & Banking Apps #

  • Auth Tokens: Store JWT tokens and API keys the right way
  • Transaction Data: Keep financial records encrypted and PCI DSS compliant
  • Biometric Data: Secure fingerprints and face ID templates safely
  • Digital Wallets: Protect cryptocurrency keys and payment info

πŸ” Enterprise & Business Apps #

  • Corporate Docs: Encrypt contracts and confidential documents
  • Employee Data: Manage credentials and personal info securely
  • API Keys: Store third-party service credentials safely
  • Audit Trails: Maintain encrypted logs for compliance

πŸ“± Consumer Apps with Real Users #

  • Password Managers: Store encrypted passwords and secure notes
  • Messaging Apps: Cache encrypted messages and media files
  • Personal Vaults: Secure storage for IDs, certificates, and important docs
  • Social Apps: Protect user data and private content

🌐 Cross-Platform Apps #

  • Consistent Security: Same protection across mobile, web, and desktop
  • Large Files: Handle encrypted images, videos, and documents efficiently
  • Offline-First: Secure local storage that works without internet

Why Choose Vault Storage? #

πŸš€ Modern apps demand modern security. Even simple applications benefit from robust, future-proof storage

Built for Real-World Applications

  • πŸ”’ Security by Default: Why worry about data breaches? Get enterprise-grade encryption out of the box
  • ⚑ Performance First: Smooth UI even with heavy encryption - operations run in background isolates
  • 🌍 True Cross-Platform: One API that works consistently across mobile, web, and desktop
  • πŸ›‘οΈ Clear Error Handling: Explicit exceptions with typed StorageError subtypes

Future-Proof Your App

  • πŸ“ˆ Scalable: Start with simple key-value storage, seamlessly add encrypted file storage as you grow
  • βœ… Compliance Ready: Already meet GDPR, HIPAA, and PCI DSS requirements without extra work
  • πŸ”§ Production Ready: Used in real-world applications handling sensitive user data
  • 🎯 Pragmatic: Simple, readable API with robust internals

Developer Experience

  • 🎨 Clean API: Simple, intuitive methods that handle complex security behind the scenes
  • πŸ“¦ Batteries Included: Error types, utilities, and comprehensive documentation
  • πŸ§ͺ Well Tested: 97.5% test coverage gives you confidence in reliability
  • πŸ“š Complete Documentation: Examples, use cases, and troubleshooting guides

Perfect for Both Simple and Complex Apps

Growing App? Start storing user preferences securely, then add document encryption later - same API.

Enterprise App? Get the security and compliance features you need without the complexity.

Consumer App? Your users' data deserves protection, and they'll notice the smooth performance.

πŸ’‘ Pro Tip: Even if you're storing "just preferences" today, using proper security from day one prevents costly migrations later when you add user accounts, premium features, or sensitive data.

Important Notes for Production Use #

⚠️ Security Disclaimer: While Vault Storage implements industry-standard encryption (AES-GCM 256-bit) and follows security best practices, no software can guarantee 100% security. Always conduct your own security audits and compliance reviews before using in production applications, especially those handling sensitive data.

πŸ”’ Security Considerations #

  • Audit Required: Perform independent security audits for applications handling sensitive data
  • Compliance: Verify that your implementation meets your specific regulatory requirements
  • Key Management: The security of your data depends on the platform's secure storage implementation
  • Testing: Thoroughly test encryption/decryption flows in your specific use case
  • Your Responsibility: You are responsible for ensuring compliance with applicable laws and regulations
  • Data Protection: Review data protection requirements for your jurisdiction and industry
  • User Consent: Ensure proper user consent for data collection and storage
  • Backup Strategy: Implement appropriate backup and recovery procedures

πŸ›‘οΈ Best Practices #

  • Regular Updates: Keep the package and dependencies updated for security patches
  • Error Handling: Implement comprehensive error handling for storage failures
  • Data Minimisation: Only store data that you actually need
  • Access Control: Implement proper access controls in your application layer

πŸ“‹ Recommendation: For mission-critical applications, consider additional security measures such as certificate pinning, runtime application self-protection (RASP), and regular penetration testing.

Getting Started #

Add vault_storage to your pubspec.yaml file:

dependencies:
  # ... other dependencies
  vault_storage: ^2.0.0 # Replace with the latest version

Then, run:

flutter pub get

Migration Guide: 1.x -> 2.0 #

This release simplifies the API and removes the BoxType-driven/Either-based surface. Key changes and how to migrate:

Why this change? #

  • Clarity and intent: Methods like saveSecure, saveNormal, and get(..., isSecure) are explicit and reduce ambiguity and misuse
  • Simpler error handling: Throwing typed StorageError exceptions simplifies flows compared to Either-based handling sprinkled across call sites
  • Less leakage of internals: Removing BoxType prevents coupling callers to storage implementation details
  • Web and files ergonomics: A single key-based file API (with auto-download on web) is easier to use than passing back metadata maps
  • Performance and maintainability: A smaller, clearer surface makes it easier to optimize internals (isolates, streaming) and evolve features safely
  • Performance and maintainability: A smaller, clearer surface makes it easier to optimise internals (isolates, streaming) and evolve features safely

Trade-offs (considered acceptable):

  • Exceptions require try/catch instead of .fold() patterns
  • Web downloads now use a sensible default filename rather than app-controlled names in this simplified API
  1. Initialisation and errors
  • Before: await storage.init() returned Either, handled via .fold()
  • After: await storage.init() throws on failure. Use try/catch.
  1. Key-value API
  • Before:
    • await storage.set(BoxType.secure, 'k', 'v')
    • final v = await storage.get<String>(BoxType.secure, 'k')
  • After:
    • await storage.saveSecure(key: 'k', value: 'v')
    • final v = await storage.get<String>('k', isSecure: true)
    • Normal data: saveNormal(...) and get(..., isSecure: false)
    • Delete: await storage.delete('k') (removes from both storages)
    • Clear: await storage.clearNormal(), await storage.clearSecure()
  1. File storage
  • Before:
    • saveSecureFile(fileBytes, fileExtension) returned metadata Map you stored and later passed to getSecureFile(metadata, downloadFileName: ...)
  • After:
    • await saveSecureFile(key: 'profile', fileBytes: bytes, originalFileName: 'x.jpg', metadata: {...})
    • Retrieve with await getFile('profile') (auto-detect secure/normal); optionally constrain via isSecure
    • Delete with await deleteFile('profile')
    • Web: files auto-download on getFile(); custom filenames are not configurable in this API
  1. Error handling
  • Before: Either<StorageError, T> results
  • After: methods throw StorageError subclasses (StorageReadError, StorageWriteError, etc.)
  1. Performance & internals
  • Large JSON/base64 handled via isolates; thresholds configurable in VaultStorageConfig
  • Secure file encryption supports streaming for large files
  • More aggressive Hive compaction strategy internally

See CHANGELOG for full details.

Quick Start #

Use the factory to create an instance and initialise once at app start:

import 'package:vault_storage/vault_storage.dart';

final storage = VaultStorage.create();
await storage.init();

// Save values
await storage.saveSecure(key: 'api_key', value: 'my_secret_key');
await storage.saveNormal(key: 'theme', value: 'dark');

// Read values (normal first, then secure)
final token = await storage.get<String>('api_key');
final theme = await storage.get<String>('theme');

// Constrain lookup to secure or normal storage
final secureOnly = await storage.get<String>('api_key', isSecure: true);
final normalOnly = await storage.get<String>('theme', isSecure: false);

The factory returns IVaultStorage and hides implementation details.

Platform Setup #

This package uses flutter_secure_storage for secure key management, which requires platform-specific configurations:

Android #

In android/app/build.gradle, set minimum SDK version to 18 or higher:

android {
    defaultConfig {
        minSdkVersion 18  // Required for KeyStore
    }
}

Note: To prevent backup-related keystore issues, consider disabling auto-backup in your AndroidManifest.xml:

<application
    android:allowBackup="false"
    android:fullBackupContent="false"
    android:dataExtractionRules="@xml/data_extraction_rules"
    ...>

iOS #

No additional configuration required. The package uses iOS Keychain by default.

macOS #

Required: Add Keychain access entitlements and configure codesigning to prevent StorageInitializationError.

1. Create or update entitlement files

macos/Runner/DebugProfile.entitlements:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.security.app-sandbox</key>
    <true/>
    <key>com.apple.security.cs.allow-jit</key>
    <true/>
    <key>com.apple.security.network.server</key>
    <true/>
    <key>com.apple.security.files.user-selected.read-write</key>
    <true/>
    <key>com.apple.security.files.downloads.read-write</key>
    <true/>
    <key>keychain-access-groups</key>
    <array>
        <string>$(AppIdentifierPrefix)$(CFBundleIdentifier)</string>
    </array>
</dict>
</plist>

macos/Runner/Release.entitlements:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.security.app-sandbox</key>
    <true/>
    <key>com.apple.security.files.user-selected.read-write</key>
    <true/>
    <key>com.apple.security.files.downloads.read-write</key>
    <true/>
    <key>keychain-access-groups</key>
    <array>
        <string>$(AppIdentifierPrefix)$(CFBundleIdentifier)</string>
    </array>
</dict>
</plist>

2. Configure Codesigning

Ensure proper codesigning is configured in your Xcode project:

  1. Open macos/Runner.xcworkspace in Xcode
  2. Select the Runner project in the navigator
  3. Go to "Signing & Capabilities" tab
  4. Ensure:
    • Team is selected (required for keychain access)
    • Bundle Identifier matches your app's identifier
    • Signing Certificate is valid
    • Keychain Sharing capability is added (should appear automatically with the entitlements)

3. Clean and rebuild after setup

flutter clean
flutter pub get
flutter run -d macos

4. Troubleshooting macOS Issues

If you still encounter StorageInitializationError:

  1. Check Console app for detailed error messages from your app
  2. Verify codesigning: Run codesign -dv --verbose=4 /path/to/your/app.app to verify signatures
  3. Reset Keychain (development only): Delete keychain entries for your app if corrupted
  4. Check entitlements: Run codesign -d --entitlements - /path/to/your/app.app to verify entitlements are applied

Why this is required: VaultStorage creates secure encryption keys using macOS Keychain during initialization. Without proper entitlements and codesigning, the system denies access to the Keychain, causing the StorageInitializationError.

Linux #

Install required system dependencies:

sudo apt-get install libsecret-1-dev libjsoncpp-dev

For runtime: libsecret-1-0 and libjsoncpp1

Windows #

No additional configuration required. Note: readAll and deleteAll operations have limitations on Windows.

Web #

The package uses WebCrypto on web. Important notes:

  • Use HTTPS in production; consider adding Strict-Transport-Security headers
  • Data is browser/domain specific and non-portable
  • Auto-downloads occur when retrieving files

Recommended header:

Strict-Transport-Security: max-age=31536000; includeSubDomains

Before running your app, you must initialise the service. This is typically done in your main.dart:

import 'package:flutter/material.dart';
import 'package:vault_storage/vault_storage.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialise the vault storage
  final storage = VaultStorage.create();
  try {
    await storage.init();
    runApp(MyApp(storage: storage));
  } on StorageError catch (e) {
    // Handle initialisation error appropriately
    debugPrint('Failed to initialise storage: ${e.message}');
    runApp(const ErrorApp());
  }
}

class MyApp extends StatelessWidget {
  final IVaultStorage storage;
  
  const MyApp({super.key, required this.storage});
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      home: MyHomePage(storage: storage),
    );
  }
}
// List keys (unique, sorted)
final allKeys = await storage.keys(); // both normal and secure; includes file keys

Usage #

Basic Usage (No Dependencies) #

Use Vault Storage directly without any state management framework:

import 'package:vault_storage/vault_storage.dart';

class StorageManager {
  static IVaultStorage? _instance;

  static Future<IVaultStorage> get instance async {
    if (_instance != null) return _instance!;
    final s = VaultStorage.create();
    await s.init();
    return _instance = s;
  }
}

// Usage example
Future<void> example() async {
  final storage = await StorageManager.instance;

  await storage.saveSecure(key: 'api_key', value: 'my_secret_key');
  final value = await storage.get<String>('api_key', isSecure: true);
  debugPrint('Retrieved API key: $value');
}

Using with Riverpod #

Create your own provider if you use Riverpod:

dependencies:
  vault_storage: ^2.0.0
  flutter_riverpod: ^2.5.0
  riverpod_annotation: ^2.3.3

dev_dependencies:
  build_runner: ^2.4.7
  riverpod_generator: ^2.3.9

Then create your own provider file: lib/providers/storage_provider.dart

import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:vault_storage/vault_storage.dart';

part 'storage_provider.g.dart';

@Riverpod(keepAlive: true)
Future<IVaultStorage> vaultStorage(VaultStorageRef ref) async {
  final implementation = VaultStorage.create();
  await implementation.init();
  ref.onDispose(() async => implementation.dispose());
  return implementation;
}

Don't forget to run code generation:

dart run build_runner build

Then use it in your widgets:

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'providers/storage_provider.dart';

class MyWidget extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return ref.watch(vaultStorageProvider).when(
      data: (storage) => YourWidget(storage: storage),
      loading: () => CircularProgressIndicator(),
      error: (error, stack) => Text('Error: $error'),
    );
  }
}

And update your main.dart:

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'providers/storage_provider.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  final container = ProviderContainer();
  try {
    await container.read(vaultStorageProvider.future);
    runApp(
      UncontrolledProviderScope(
        container: container,
        child: const MyApp(),
      ),
    );
  } catch (error) {
    runApp(const ErrorApp());
  }
}

Key-Value Storage #

Store and retrieve simple key-value pairs:

// Secure data (encrypted)
await storage.saveSecure(key: 'user_token', value: 'jwt_token_here');
await storage.saveSecure(key: 'user_credentials', value: {
  'username': 'john_doe',
  'password': 'hashed_password',
});

// Normal data (faster, unencrypted)
await storage.saveNormal(key: 'theme_mode', value: 'dark');
await storage.saveNormal(key: 'language', value: 'en');

// Retrieve data
final token = await storage.get<String>('user_token', isSecure: true);
final theme = await storage.get<String>('theme_mode', isSecure: false);

File Storage (Secure and Normal) #

For images, documents, or any binary data:

import 'dart:typed_data';

Future<void> handleFileStorage(IVaultStorage storage) async {
  final Uint8List imageData = /* from picker/network */ Uint8List(0);

  // Save a secure file (encrypted)
  await storage.saveSecureFile(
    key: 'profile_image',
    fileBytes: imageData,
    originalFileName: 'avatar.jpg',
    metadata: {'userId': '123'}, // optional user metadata
  );

  // Save a normal file (unencrypted)
  await storage.saveNormalFile(
    key: 'cached_document',
    fileBytes: imageData,
    originalFileName: 'document.pdf',
  );

  // Retrieve file bytes by key
  final secureBytes = await storage.getFile('profile_image'); // web auto-downloads
  final normalBytes = await storage.getFile('cached_document', isSecure: false);

  // Delete files
  await storage.deleteFile('profile_image');
  await storage.deleteFile('cached_document');
}

Note on web: When you call getFile(), the browser automatically downloads the file using a sensible default filename derived from the stored extension. Custom download filenames are not configurable in this simplified API.

Storage Classes Under the Hood #

Internally, Vault Storage maintains separate boxes for normal/secure key-value data and normal/secure files. The public API abstracts this; you only provide keys and optional isSecure where relevant.

Platform-Specific Behaviour #

The package automatically handles platform differences to provide the best user experience:

File Retrieval Behaviour

  • Web: Auto-downloads file and returns Uint8List
  • Native: Returns Uint8List only (no download)

File Storage Implementation

  • Native platforms (iOS, Android, macOS, Windows, Linux): Files are stored in the app's documents directory using the file system
  • Web: Files are stored as base64-encoded strings in encrypted Hive boxes (browser storage)

Automatic MIME Type Detection (Web)

For web downloads, MIME types are inferred from file extensions (PDF, images, common docs, audio/video, archives, JSON/TXT, etc.). If unknown, defaults to application/octet-stream.

No code changes are required - the package handles platform detection and optimisation automatically.

Web Compatibility #

  • Native: Files are stored in the app's documents directory
  • Web: Files are stored as base64-encoded strings in Hive (secure files encrypted), and auto-download when retrieved

Initialisation in main() #

import 'package:flutter/material.dart';
import 'package:vault_storage/vault_storage.dart';

late final IVaultStorage vaultStorage;

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialise storage
  vaultStorage = VaultStorage.create();
  await vaultStorage.init();
  debugPrint('Storage initialised successfully');

  runApp(const MyApp());
}

// Use the service anywhere in your app
Future<void> useStorage() async {
  await vaultStorage.saveSecure(key: 'api_key', value: 'my_secret_key');
}

Error Handling #

APIs throw typed exceptions that extend StorageError. Use try/catch:

try {
  await vaultStorage.saveSecure(key: 'k', value: 'v');
  final v = await vaultStorage.get<String>('k', isSecure: true);
} on StorageInitializationError catch (e) {
  debugPrint('Storage not initialised: ${e.message}');
} on StorageReadError catch (e) {
  debugPrint('Read failed: ${e.message}');
} on StorageWriteError catch (e) {
  debugPrint('Write failed: ${e.message}');
} on StorageSerializationError catch (e) {
  debugPrint('Serialization failed: ${e.message}');
}

Storage Management #

// Delete a key from both storages
await vaultStorage.delete('api_key');

// Clear storages
await vaultStorage.clearNormal();
await vaultStorage.clearSecure();

// Inspect keys
final keys = await vaultStorage.keys(includeFiles: true);

// Dispose (e.g., on shutdown)
await vaultStorage.dispose();

Performance Tuning #

Tweak thresholds at startup using VaultStorageConfig:

// Optional: tune for your workload
VaultStorageConfig.jsonIsolateThreshold = 15000; // chars
VaultStorageConfig.base64IsolateThreshold = 100000; // bytes
VaultStorageConfig.secureFileStreamingThresholdBytes = 1 * 1024 * 1024; // 1MB

Troubleshooting #

Common Initialisation Errors #

"Failed to create/decode secure key"

This error typically occurs when flutter_secure_storage cannot access the platform's secure storage:

macOS: Ensure keychain access entitlements are properly configured (see Platform Setup above)

Android: Check that minSdkVersion >= 18 and consider disabling auto-backup

Solution: Verify platform-specific setup requirements and restart your app after configuration changes

App Crashes on First Launch

If the app crashes during storage initialisation:

  1. Check that all platform requirements are met
  2. Ensure proper error handling in your main() function:
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  final storage = VaultStorage.create();
  final initResult = await storage.init();
  
  initResult.fold(
    (error) {
      print('Storage initialisation failed: ${error.message}');
      // Show error screen or fallback UI
      runApp(MaterialApp(
        home: Scaffold(
          body: Center(
            child: Text('Storage initialisation failed: ${error.message}'),
          ),
        ),
      ));
    },
    (_) => runApp(MyApp(storage: storage)),
  );
}

Web Storage Issues

For web applications:

  • Ensure HTTPS is enabled for production
  • Check browser compatibility with WebCrypto
  • Verify that local storage is not disabled

Debug Mode #

To get more detailed error information, check the console output when initialisation fails. The package provides detailed error messages for different failure scenarios.

Testing #

To run tests:

flutter test

Dependencies #

  • hive_ce_flutter: Local storage database ;- flutter_secure_storage: Secure key storage
  • cryptography_plus: AES-GCM encryption
  • web: Modern web APIs for web downloads

Platform Support #

  • βœ… Android
  • βœ… iOS
  • βœ… Web
  • βœ… macOS
  • βœ… Windows
  • βœ… Linux

License #

This project is licensed under the MIT License.


6
likes
160
points
471
downloads

Publisher

verified publisherafenso.com

Weekly Downloads

A package for secure key-value and file storage using Hive and flutter_secure_storage.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

cryptography_plus, flutter, flutter_secure_storage, hive_ce, hive_ce_flutter, path_provider, uuid, web

More

Packages that depend on vault_storage