Security & Persistence
Fasq provides a robust interface for securely persisting your query cache. While the core package includes the definitions, you can plug in any encryption or storage implementations.
Overview
[!TIP] While you can implement your own security plugin, we recommend using the pre-built fasq_security package which provides enterprise-grade AES-GCM encryption and encrypted SQLite persistence out of the box.
Security in Fasq is handled through the SecurityPlugin interface, which coordinates three providers:
- EncryptionProvider: Encrypts/decrypts data.
- PersistenceProvider: Stores data (e.g., SQLite, SharedPreferences).
- SecurityProvider: Manages encryption keys securely.
Configuration
To enable security and persistence, pass a SecurityPlugin to your QueryClient.
final client = QueryClient(
securityPlugin: MySecurePlugin(), // Your implementation
);Once configured, you can mark specific queries as secure.
QueryBuilder<String>(
queryKey: 'auth_token'.toQueryKey(),
queryFn: () => login(),
options: const QueryOptions(
isSecure: true, // Data will be handled by the plugin
maxAge: Duration(minutes: 30), // Mandatory for secure entries
),
builder: (context, state) => /* ... */,
)Creating a Plugin
You can build a custom security plugin by implementing SecurityPlugin.
class MySecurePlugin implements SecurityPlugin {
@override
final String name = 'MySecurePlugin';
@override
final String version = '1.0.0';
@override
bool get isSupported => !kIsWeb; // Example: Disable on web
@override
EncryptionProvider createEncryptionProvider() => MyAESProvider();
@override
PersistenceProvider createPersistenceProvider() => MyFileStorage();
@override
SecurityProvider createStorageProvider() => MyKeychainProvider();
}Best Practices
1. Secure Sensitive Data
Always mark tokens, PII, and financial data with isSecure: true.
2. Set Max Age
Secure data should not live forever. Always set maxAge to a reasonable session length.
QueryOptions(
isSecure: true,
maxAge: Duration(minutes: 15),
)3. Clear on Logout
When a user logs out, ensure you clear the cache.
await client.resetQueries(); // Clears memory and calls persistence remove