Key Hiding
Protect sensitive AppTrove SDK credentials (SDK Key, Secret ID, Secret Key) by storing them securely using Flutter's secure storage capabilities. This prevents keys from being exposed in plain text within your app's source code, reducing the risk of unauthorized access and fraudulent activities.
Purpose
Key hiding is essential for securing your AppTrove SDK integration:
- Safeguard SDK Key, Secret ID, and Secret Key from reverse engineering
- Store credentials in encrypted storage using
flutter_secure_storage
- Automatically retrieve keys during app initialization
- Provide fallback mechanisms for key management
- Prevent fraudulent activities by securing SDK credentials
This feature works in conjunction with SDK Signing to provide comprehensive security for your Trackier SDK integration.
Prerequisites
- AppTrove SDK: Flutter SDK properly integrated
- Flutter: Version 3.0.0 or later
- Dependencies:
flutter_secure_storage
package - Trackier Panel: SDK Key, Secret ID, and Secret Key retrieved
- Permissions: Internet access
Implementation
Follow these steps to implement secure key storage in your Flutter app:
Step 1: Add Dependencies
Add the flutter_secure_storage
package to your pubspec.yaml
:
dependencies:
flutter:
sdk: flutter
trackier_sdk: ^latest_version
flutter_secure_storage: ^9.0.0
Reference: This is reference we add library and add key and show in logs after first launch remove the key it will store locally.
Step 2: Create Secure Storage Service
Create a service to handle secure storage operations:
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class SecureStorageService {
static const FlutterSecureStorage _storage = FlutterSecureStorage();
static const String _trackierKey = 'trackier_sdk_key';
static const String _secretId = 'trackier_secret_id';
static const String _secretKey = 'trackier_secret_key';
// Store the Trackier SDK key securely
static Future<void> storeTrackierKey(String key) async {
await _storage.write(key: _trackierKey, value: key);
}
// Retrieve the Trackier SDK key securely
static Future<String?> getTrackierKey() async {
return await _storage.read(key: _trackierKey);
}
// Store the Secret ID securely
static Future<void> storeSecretId(String secretId) async {
await _storage.write(key: _secretId, value: secretId);
}
// Retrieve the Secret ID securely
static Future<String?> getSecretId() async {
return await _storage.read(key: _secretId);
}
// Store the Secret Key securely
static Future<void> storeSecretKey(String secretKey) async {
await _storage.write(key: _secretKey, value: secretKey);
}
// Retrieve the Secret Key securely
static Future<String?> getSecretKey() async {
return await _storage.read(key: _secretKey);
}
// Clear all stored credentials
static Future<void> clearAllCredentials() async {
await _storage.delete(key: _trackierKey);
await _storage.delete(key: _secretId);
await _storage.delete(key: _secretKey);
}
}
Step 3: Create App Configuration
Create a configuration class to manage default values and app settings:
class AppConfig {
// Replace these with your actual Trackier SDK credentials
// IMPORTANT: Remove these keys after first run - they will be stored securely
static const String defaultTrackierKey = "YOUR_TRACKIER_SDK_KEY_HERE";
static const String defaultSecretId = "YOUR_SECRET_ID_HERE";
static const String defaultSecretKey = "YOUR_SECRET_KEY_HERE";
// Environment configuration
static const String environment = "development"; // or "production"
}
Step 4: Update Main Application
Update your main.dart
to use secure storage for key management:
import 'package:flutter/material.dart';
import 'package:trackier_sdk/trackier_sdk.dart';
import 'secure_storage_service.dart';
import 'app_config.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Trackier SDK Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
void initState() {
super.initState();
initPlatformState();
}
Future<void> initPlatformState() async {
try {
// Get the Trackier key from secure storage
String? trackierKey = await SecureStorageService.getTrackierKey();
String? secretId = await SecureStorageService.getSecretId();
String? secretKey = await SecureStorageService.getSecretKey();
// If no keys are stored, use default keys and store them securely
if (trackierKey == null) {
trackierKey = AppConfig.defaultTrackierKey;
await SecureStorageService.storeTrackierKey(trackierKey);
print(' Using default Trackier key: $trackierKey');
} else {
print('Retrieved Trackier key from secure storage: $trackierKey');
}
if (secretId == null) {
secretId = AppConfig.defaultSecretId;
await SecureStorageService.storeSecretId(secretId);
print(' Using default Secret ID: $secretId');
} else {
print(' Retrieved Secret ID from secure storage: $secretId');
}
if (secretKey == null) {
secretKey = AppConfig.defaultSecretKey;
await SecureStorageService.storeSecretKey(secretKey);
print(' Using default Secret Key: $secretKey');
} else {
print(' Retrieved Secret Key from secure storage: $secretKey');
}
// Configure SDK with secure credentials
TrackerSDKConfig trackerSDKConfig = TrackerSDKConfig(
trackierKey,
AppConfig.environment,
);
// Set app secrets for SDK signing
trackerSDKConfig.setAppSecret(secretId, secretKey);
// Initialize SDK
await TrackierSDK.initialize(trackerSDKConfig);
print('Trackier SDK initialized successfully with secure credentials');
} catch (e) {
print('Error initializing Trackier SDK: $e');
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Trackier SDK Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Trackier SDK Initialized',
style: Theme.of(context).textTheme.headlineSmall,
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () async {
// Clear stored credentials (for testing)
await SecureStorageService.clearAllCredentials();
print('🗑️ Cleared all stored credentials');
},
child: Text('Clear Credentials'),
),
],
),
),
);
}
}
Step 5: Install Dependencies
Run the following command to install the required dependencies:
flutter pub get
Key Management
Updating Keys
To update your SDK keys:
- Update in Trackier Panel: First, update your keys in the Trackier Panel
- Clear Stored Keys: Use the clear function to remove old keys:
await SecureStorageService.clearAllCredentials();
- Update AppConfig: Temporarily update the default keys in
app_config.dart
:static const String defaultTrackierKey = "YOUR_NEW_SDK_KEY";
static const String defaultSecretId = "YOUR_NEW_SECRET_ID";
static const String defaultSecretKey = "YOUR_NEW_SECRET_KEY"; - Run the App: The new keys will be stored securely on first run
- Remove from AppConfig: Once keys are stored, remove them from
app_config.dart
:static const String defaultTrackierKey = ""; // Remove after first run
static const String defaultSecretId = ""; // Remove after first run
static const String defaultSecretKey = ""; // Remove after first run
Removing Keys from AppConfig
Important: After the first successful run, remove your actual keys from app_config.dart
and replace them with empty strings or placeholder values:
class AppConfig {
// Remove actual keys after first run - they will be stored securely
static const String defaultTrackierKey = ""; // Remove after first run
static const String defaultSecretId = ""; // Remove after first run
static const String defaultSecretKey = ""; // Remove after first run
// Environment configuration
static const String environment = "development"; // or "production"
}
This ensures that your actual keys are never committed to version control and are only stored in the device's secure storage.
Security Features
Encrypted Storage
The flutter_secure_storage
package provides:
- iOS: Uses Keychain Services for secure storage
- Android: Uses EncryptedSharedPreferences with AES encryption
- Web: Uses localStorage with encryption (when supported)
Key Management
- Automatic Storage: Keys are automatically stored when first accessed
- Secure Retrieval: Keys are retrieved from encrypted storage
- Fallback Mechanism: Default keys are used if secure storage is empty
- Clear Function: Ability to clear all stored credentials
Best Practices
- Never Hardcode Keys: Always use secure storage instead of hardcoding credentials
- Use Environment Variables: Store default keys in environment-specific configuration
- Regular Key Rotation: Periodically update your SDK keys in the Trackier Panel
- Debug Mode: Use debug mode during development to disable organic tracking
- Error Handling: Implement proper error handling for storage operations
Troubleshooting
Common Issues
- Keys Not Stored: Ensure
flutter_secure_storage
is properly added to dependencies - Permission Errors: Check that your app has proper permissions for secure storage
- Initialization Failures: Verify that your SDK keys are correct and valid
- Storage Access: Ensure the device supports secure storage (most modern devices do)
Debug Information
Enable debug logging to troubleshoot issues:
// Add this to your initPlatformState method for debugging
if (AppConfig.debugMode) {
print('🔍 Debug: Checking secure storage...');
String? storedKey = await SecureStorageService.getTrackierKey();
print('🔍 Debug: Stored key exists: ${storedKey != null}');
}
Next Steps
After implementing key hiding:
- Test the Integration: Verify that events are being tracked correctly
- Monitor Dashboard: Check your Trackier Panel for incoming data
- Implement Events: Add custom event tracking throughout your app
- Security Review: Regularly review and update your security practices