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

🧠 Test Your Knowledge

What type of data should you store in Secure Storage?