flutter_secure_storage_x 12.0.0
flutter_secure_storage_x: ^12.0.0 copied to clipboard
flutter_secure_storage_x provides API to store data in secure storage. Keychain is used in iOS, KeyStore based solution is used in Android.
flutter_secure_storage_x #
This package is a fork of the popular flutter_secure_storage package. The original project aims to provide a comprehensive set of features and options to cover a wide range of needs.
This fork builds upon the original work with a more focused approach. The philosophy is to ensure long-term stability and maintainability by offering a minimal, robust API for the most common encrypted storage use cases. This pragmatic direction provides a simple and reliable solution for developers who prioritize these aspects.
The plugin utilizes platform-specific secure storage mechanisms:
- On iOS, Keychain is used.
- On Android, AES encryption with KeyStore is used.
- For Linux,
libsecretis utilized.
For more detailed information and usage examples, please refer to the example app.
Platform Implementation #
Please note that this table represents the functions implemented in this repository and it is possible that changes haven't yet been released on pub.dev
| read | write | delete | containsKey | readAll | deleteAll | isCupertinoProtectedDataAvailable | onCupertinoProtectedDataAvailabilityChanged | |
|---|---|---|---|---|---|---|---|---|
| Android | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ||
| iOS | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Windows | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ||
| Linux | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ||
| macOS | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ (on macOS 12 and newer) |
| Web | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Getting Started #
If not already present, call WidgetsFlutterBinding.ensureInitialized() in your main() function before interacting with the MethodChannel. See this issue for more information: https://github.com/mogol/flutter_secure_storage/issues/336
import 'package:flutter_secure_storage_x/flutter_secure_storage_x.dart';
// Create storage
final storage = FlutterSecureStorage();
// Read value
String? value = await storage.read(key: key);
// Read all values
Map<String, String> allValues = await storage.readAll();
// Delete value
await storage.delete(key: key);
// Delete all
await storage.deleteAll();
// Write value
await storage.write(key: key, value: value);
Important Considerations #
Background Access #
By default, this package configures both iOS Keychain and Android KeyStore to only allow data access when the device is unlocked. This is a security feature to protect sensitive data.
This means that if your app is launched in the background (e.g., by a push notification or background fetch) while the device is locked, any attempts to access the secure storage will fail.
If your application requires background access to the storage, you must configure this explicitly. This allows fetching secure values while the app is backgrounded by specifying first_unlock or first_unlock_this_device. The default, if not specified, is unlocked.
iOS:
Use the iOptions parameter with an appropriate KeychainAccessibility value, such as KeychainAccessibility.first_unlock_this_device.
An example using KeychainAccessibility.first_unlock:
final options = IOSOptions(
accessibility: KeychainAccessibility.first_unlock,
);
await storage.write(
key: key,
value: value,
iOptions: options,
);
Android: The default Android settings generally allow background access as long as the device has been unlocked once since booting. No special configuration is typically needed for this use case.
Platform-specific configuration #
Android #
In [project]/android/app/build.gradle set minSdkVersion to >= 23.
android {
...
defaultConfig {
...
minSdkVersion 23
...
}
}
Note: By default, Android backs up data on Google Drive. This can cause an exception: java.security.InvalidKeyException: Failed to unwrap key.
You need to:
- disable autobackup, details
- exclude sharedprefs
FlutterSecureStorageused by the plugin, details
DataStore support has been available since v10.0.0. When using DataStore, set the options as follows.
AndroidOptions _getAndroidOptions() => const AndroidOptions(
dataStore: true,
);
Web #
The web implementation uses WebCrypto and should be considered experimental. It only works on secure contexts (HTTPS or localhost). Feedback is welcome to help improve it.
The intent is for the browser to create the private key, and as a result, the encrypted strings in localStorage are not portable to other browsers or other machines and will only work on the same domain.
It is VERY important that you have HTTP Strict Transport Security enabled and the proper headers applied to your responses, or you could be subject to a JavaScript hijacking attack.
Please see:
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
- https://www.netsparker.com/blog/web-security/http-security-headers/
WASM support
Supported from v2.0.0.
application-specific key option
On the web, all keys are stored in localStorage. This package offers an option to wrap these stored keys with an application-specific key to make analysis more difficult.
final _storage = const FlutterSecureStorageX(
webOptions: WebOptions(
wrapKey: '${your_application_specific_key}',
wrapKeyIv: '${your_application_specific_iv}',
),
);
This option encrypts the key stored in localStorage with WebCrypto wrapKey. It is decrypted with WebCrypto unwrapKey when used.
Generating and managing application-specific keys requires careful attention from developers. See (https://github.com/mogol/flutter_secure_storage/issues/726) for more information.
Linux #
You need libsecret-1-dev and libjsoncpp-dev on your machine to build the project, and libsecret-1-0 and libjsoncpp1 to run the application (add them as dependencies after packaging your app). If you are using Snapcraft to build the project, use the following:
parts:
uet-lms:
source: .
plugin: flutter
flutter-target: lib/main.dart
build-packages:
- libsecret-1-dev
- libjsoncpp-dev
stage-packages:
- libsecret-1-0
- libjsoncpp-dev
In addition to libsecret, you also need a keyring service. For this, you can use either gnome-keyring (for GNOME users), ksecretsservice (for KDE users), or other lightweight providers like secret-service.
macOS #
You also need to add the Keychain Sharing capability to your macOS runner. To achieve this, please add the following in both macos/Runner/DebugProfile.entitlements and macos/Runner/Release.entitlements (you need to change both files).
<key>keychain-access-groups</key>
<array/>
If your application is configured to use App Groups, you will need to add the name of the App Group to the keychain-access-groups argument above. Failure to do so will result in values appearing to be written successfully but never actually being written at all. For example, if your app has an App Group named "aoeu", then the value above would instead read:
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)aoeu</string>
</array>
If you are configuring this value through Xcode, then the string you set in the Keychain Sharing section would simply read "aoeu", with Xcode appending the $(AppIdentifierPrefix) when it saves the configuration.
Windows #
You need the C++ ATL libraries installed along with the rest of the Visual Studio Build Tools. Download them from here and ensure the C++ ATL component under 'Optional' is also installed.
Integration Tests #
Run the following command from flutter_secure_storage_x/example directory:
flutter test integration_test
This command runs tests on the currently active device.