Flutter Secure Storage
Encrypted storage for sensitive data in Flutter
🔐 What is Secure Storage?
Flutter Secure Storage provides encrypted key-value storage for sensitive data like passwords, tokens, and API keys. It uses Keychain on iOS and KeyStore on Android, ensuring your sensitive information remains protected with platform-native security.
// Add to pubspec.yaml
dependencies:
flutter_secure_storage: ^9.0.0
// Store sensitive data securely
await storage.write(key: 'token', value: 'secret123');
Key Features
Encrypted
All data is encrypted automatically
await storage.write(
key: 'password', ...);
Platform Native
Uses iOS Keychain & Android KeyStore
// Secure by default
// No extra config needed
Key-Value
Simple API like Shared Preferences
String? token =
await storage.read(key: 'token');
Secure
Perfect for sensitive data
// Passwords, tokens,
// API keys, etc.
🔹 Installation
Add the package to your Flutter project:
# pubspec.yaml
dependencies:
flutter:
sdk: flutter
flutter_secure_storage: ^9.0.0
Android Configuration (minSdkVersion 18+):
In
android/app/build.gradle
, ensure:
android {
defaultConfig {
minSdkVersion 18
}
}
🔹 Basic Usage
Create an instance and start storing data:
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
// Create storage instance
final storage = FlutterSecureStorage();
// Write data
await storage.write(key: 'username', value: 'john_doe');
await storage.write(key: 'password', value: 'mySecretPass123');
await storage.write(key: 'api_token', value: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...');
print('Sensitive data stored securely!');
Result:
✅ Sensitive data stored securely!
🔹 Reading Data
Retrieve encrypted data from storage:
// Read single value
String? username = await storage.read(key: 'username');
String? password = await storage.read(key: 'password');
String? token = await storage.read(key: 'api_token');
print('Username: $username');
print('Password: ${password != null ? "***" : "Not found"}');
print('Token: ${token?.substring(0, 10)}...');
// Read all values
Map<String, String> allValues = await storage.readAll();
print('Total stored items: ${allValues.length}');
Output:
Username: john_doe
Password: ***
Token: eyJhbGciOi...
Total stored items: 3
🔹 Deleting Data
Remove specific keys or clear all data:
// Delete specific key
await storage.delete(key: 'password');
print('Password deleted');
// Check if key exists
bool hasToken = await storage.containsKey(key: 'api_token');
print('Has token: $hasToken');
// Delete all data
await storage.deleteAll();
print('All secure data cleared');
Output:
Password deleted
Has token: true
All secure data cleared
🔹 Storage Options
Customize storage behavior with options:
// Create storage with custom options
const storage = FlutterSecureStorage(
aOptions: AndroidOptions(
encryptedSharedPreferences: true,
),
iOptions: IOSOptions(
accessibility: KeychainAccessibility.first_unlock,
),
);
// Android Options
AndroidOptions androidOptions = const AndroidOptions(
encryptedSharedPreferences: true,
resetOnError: true,
);
// iOS Options
IOSOptions iosOptions = const IOSOptions(
accessibility: KeychainAccessibility.unlocked_this_device,
accountName: 'MyApp',
);
// Use with options
await storage.write(
key: 'secure_key',
value: 'secure_value',
aOptions: androidOptions,
iOptions: iosOptions,
);
🔹 Authentication Example
Store and manage user authentication tokens:
class AuthService {
final storage = FlutterSecureStorage();
// Save login credentials
Future<void> saveCredentials(String username, String token) async {
await storage.write(key: 'username', value: username);
await storage.write(key: 'auth_token', value: token);
await storage.write(key: 'login_time', value: DateTime.now().toIso8601String());
}
// Get auth token
Future<String?> getAuthToken() async {
return await storage.read(key: 'auth_token');
}
// Check if user is logged in
Future<bool> isLoggedIn() async {
String? token = await storage.read(key: 'auth_token');
return token != null && token.isNotEmpty;
}
// Logout - clear credentials
Future<void> logout() async {
await storage.delete(key: 'username');
await storage.delete(key: 'auth_token');
await storage.delete(key: 'login_time');
}
// Get user info
Future<Map<String, String?>> getUserInfo() async {
return {
'username': await storage.read(key: 'username'),
'token': await storage.read(key: 'auth_token'),
'loginTime': await storage.read(key: 'login_time'),
};
}
}
// Usage
final authService = AuthService();
// Login
await authService.saveCredentials('john_doe', 'jwt_token_here');
// Check login status
bool loggedIn = await authService.isLoggedIn();
print('Logged in: $loggedIn');
// Logout
await authService.logout();
🔹 Complete Login Example
A simple login page with secure storage:
class LoginPage extends StatefulWidget {
@override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final storage = FlutterSecureStorage();
final usernameController = TextEditingController();
final passwordController = TextEditingController();
@override
void initState() {
super.initState();
checkLoginStatus();
}
Future<void> checkLoginStatus() async {
String? savedUsername = await storage.read(key: 'username');
if (savedUsername != null) {
// User already logged in
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
}
}
Future<void> login() async {
String username = usernameController.text;
String password = passwordController.text;
// Validate credentials (simplified)
if (username.isNotEmpty && password.isNotEmpty) {
// Store credentials securely
await storage.write(key: 'username', value: username);
await storage.write(key: 'password', value: password);
// Navigate to home
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Secure Login')),
body: Padding(
padding: EdgeInsets.all(16),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: usernameController,
decoration: InputDecoration(labelText: 'Username'),
),
SizedBox(height: 16),
TextField(
controller: passwordController,
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
),
SizedBox(height: 24),
ElevatedButton(
onPressed: login,
child: Text('Login'),
),
],
),
),
);
}
}
🔹 Migration from Shared Preferences
Move existing data to secure storage:
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
Future<void> migrateToSecureStorage() async {
final prefs = await SharedPreferences.getInstance();
final storage = FlutterSecureStorage();
// Get sensitive data from SharedPreferences
String? token = prefs.getString('auth_token');
String? apiKey = prefs.getString('api_key');
if (token != null) {
// Move to secure storage
await storage.write(key: 'auth_token', value: token);
// Remove from SharedPreferences
await prefs.remove('auth_token');
}
if (apiKey != null) {
await storage.write(key: 'api_key', value: apiKey);
await prefs.remove('api_key');
}
print('Migration completed!');
}
🔹 Best Practices
- Sensitive Data Only: Use for passwords, tokens, API keys
- Not for Large Data: Keep stored data small and minimal
- Handle Errors: Wrap operations in try-catch blocks
- Clear on Logout: Always delete credentials when user logs out
- Don't Log Values: Never print sensitive data in production
- Biometric Lock: Consider adding biometric authentication
🔹 When to Use
✅ Use Secure Storage for:
- Authentication tokens (JWT, OAuth)
- User passwords and PINs
- API keys and secrets
- Credit card information
- Private encryption keys
❌ Don't Use for:
- User preferences (use Shared Preferences)
- Large datasets (use SQLite or Hive)
- Public configuration data
- Cached images or files