Skip to main content

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
note

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:

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:

lib/secure_storage_service.dart
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:

lib/app_config.dart
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:

lib/main.dart
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:

  1. Update in Trackier Panel: First, update your keys in the Trackier Panel
  2. Clear Stored Keys: Use the clear function to remove old keys:
    await SecureStorageService.clearAllCredentials();
  3. 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";
  4. Run the App: The new keys will be stored securely on first run
  5. 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:

lib/app_config.dart
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

  1. Never Hardcode Keys: Always use secure storage instead of hardcoding credentials
  2. Use Environment Variables: Store default keys in environment-specific configuration
  3. Regular Key Rotation: Periodically update your SDK keys in the Trackier Panel
  4. Debug Mode: Use debug mode during development to disable organic tracking
  5. Error Handling: Implement proper error handling for storage operations

Troubleshooting

Common Issues

  1. Keys Not Stored: Ensure flutter_secure_storage is properly added to dependencies
  2. Permission Errors: Check that your app has proper permissions for secure storage
  3. Initialization Failures: Verify that your SDK keys are correct and valid
  4. 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:

  1. Test the Integration: Verify that events are being tracked correctly
  2. Monitor Dashboard: Check your Trackier Panel for incoming data
  3. Implement Events: Add custom event tracking throughout your app
  4. Security Review: Regularly review and update your security practices

Support

For further assistance with key hiding implementation: