The Secure Storage API provides access to the device’s native secure storage systems - Keychain on iOS and Keystore on Android. Use it to store sensitive data like tokens, passwords, and API keys.
Usage
Store and retrieve secure data:
use Native\Mobile\Facades\SecureStorage;
// Store a value
SecureStorage::set('api_token', 'secret-token-here');
// Retrieve a value
$token = SecureStorage::get('api_token');
// Delete a value
SecureStorage::delete('api_token');
Storing Data
Store sensitive data securely in the device’s keychain or keystore:
use Native\Mobile\Facades\SecureStorage;
$success = SecureStorage::set('user_token', $token);
if ($success) {
// Value stored successfully
} else {
// Failed to store value
}
Storing Null Values
You can store null to clear a value while keeping the key:
SecureStorage::set('user_token', null);
Retrieving Data
Retrieve securely stored values:
$token = SecureStorage::get('user_token');
if ($token === null) {
// Key doesn't exist or value is null
} else {
// Use the token
}
The get() method returns null if the key doesn’t exist or if the stored value is an empty string.
Deleting Data
Permanently remove a value from secure storage:
$success = SecureStorage::delete('user_token');
if ($success) {
// Value deleted successfully
} else {
// Failed to delete value (may not exist)
}
Methods Reference
set(string $key, ?string $value)
Stores a value securely in the native keychain or keystore.
Parameters:
$key (string) - The key to store the value under
$value (string|null) - The value to store securely
Returns: bool - true if successfully stored, false otherwise
$success = SecureStorage::set('api_key', 'sk_live_123456');
get(string $key)
Retrieves a securely stored value.
Parameters:
$key (string) - The key to retrieve the value for
Returns: string|null - The stored value, or null if not found
$apiKey = SecureStorage::get('api_key');
if ($apiKey) {
// Use the API key
}
delete(string $key)
Removes a value from secure storage.
Parameters:
$key (string) - The key to delete the value for
Returns: bool - true if successfully deleted, false otherwise
$deleted = SecureStorage::delete('api_key');
Examples
Storing Authentication Tokens
use Livewire\Component;
use Native\Mobile\Facades\SecureStorage;
class Auth extends Component
{
public function login($email, $password)
{
$response = Http::post('/api/login', [
'email' => $email,
'password' => $password,
]);
if ($response->successful()) {
$token = $response->json('token');
// Store token securely
SecureStorage::set('auth_token', $token);
return redirect()->route('dashboard');
}
session()->flash('error', 'Invalid credentials');
}
public function logout()
{
// Remove stored token
SecureStorage::delete('auth_token');
return redirect()->route('login');
}
}
Auto-Login with Stored Credentials
use Livewire\Component;
use Native\Mobile\Facades\SecureStorage;
class LoginForm extends Component
{
public function mount()
{
// Check for stored token
$token = SecureStorage::get('auth_token');
if ($token) {
// Verify token with API
$response = Http::withToken($token)->get('/api/user');
if ($response->successful()) {
// Token is valid, log user in
auth()->login($response->json('user'));
return redirect()->route('dashboard');
} else {
// Token expired, remove it
SecureStorage::delete('auth_token');
}
}
}
public function render()
{
return view('livewire.login-form');
}
}
Storing API Credentials
use Native\Mobile\Facades\SecureStorage;
class ApiConfiguration
{
public function configure($apiKey, $apiSecret)
{
// Store API credentials securely
$keyStored = SecureStorage::set('stripe_api_key', $apiKey);
$secretStored = SecureStorage::set('stripe_api_secret', $apiSecret);
if ($keyStored && $secretStored) {
return true;
}
return false;
}
public function getApiClient()
{
$apiKey = SecureStorage::get('stripe_api_key');
$apiSecret = SecureStorage::get('stripe_api_secret');
if (!$apiKey || !$apiSecret) {
throw new Exception('API credentials not configured');
}
return new StripeClient($apiKey, $apiSecret);
}
public function clearCredentials()
{
SecureStorage::delete('stripe_api_key');
SecureStorage::delete('stripe_api_secret');
}
}
User Preferences with Sensitive Data
use Native\Mobile\Facades\SecureStorage;
class UserSettings extends Component
{
public $email;
public $notificationsEnabled;
public function mount()
{
// Load settings
$this->email = SecureStorage::get('user_email');
$this->notificationsEnabled = SecureStorage::get('notifications') === 'true';
}
public function save()
{
// Save email securely
SecureStorage::set('user_email', $this->email);
// Save preference
SecureStorage::set('notifications', $this->notificationsEnabled ? 'true' : 'false');
session()->flash('message', 'Settings saved');
}
public function render()
{
return view('livewire.user-settings');
}
}
Encryption Key Storage
use Native\Mobile\Facades\SecureStorage;
use Illuminate\Support\Str;
class EncryptionManager
{
public function getOrCreateEncryptionKey(): string
{
$key = SecureStorage::get('encryption_key');
if (!$key) {
// Generate new encryption key
$key = Str::random(32);
SecureStorage::set('encryption_key', $key);
}
return $key;
}
public function encrypt(string $data): string
{
$key = $this->getOrCreateEncryptionKey();
return encrypt($data, $key);
}
public function decrypt(string $encryptedData): string
{
$key = $this->getOrCreateEncryptionKey();
return decrypt($encryptedData, $key);
}
public function rotateKey(): void
{
// Generate new key
$newKey = Str::random(32);
SecureStorage::set('encryption_key', $newKey);
}
}
iOS (Keychain)
On iOS, Secure Storage uses the Keychain Services API:
- Data is encrypted and stored in the device’s Keychain
- Data persists across app reinstalls (if enabled)
- Data is automatically backed up to iCloud Keychain (if user has it enabled)
- Data is protected by device passcode/biometric authentication
- Data is isolated per app (other apps cannot access your data)
Security Features:
- Hardware-backed encryption on devices with Secure Enclave
- Automatic encryption at rest
- Protected by device lock
Android (Keystore)
On Android, Secure Storage uses the Android Keystore System:
- Data is encrypted using hardware-backed keys (on supported devices)
- Data is isolated per app
- Data does NOT persist across app uninstalls
- Data is protected by device lock on Android 6.0+
Security Features:
- Hardware-backed encryption on devices with Trusted Execution Environment (TEE)
- Automatic encryption at rest
- Protected by device lock
- StrongBox Keymaster support on Android 9+ (devices with dedicated security chip)
Best Practices
1. Only Store Sensitive Data
Use Secure Storage only for sensitive data. For regular preferences, use Laravel’s cache or session:
// Good - Secure Storage for tokens
SecureStorage::set('auth_token', $token);
// Bad - Use regular cache for non-sensitive data
// SecureStorage::set('theme', 'dark');
cache()->put('theme', 'dark');
2. Always Check Return Values
Both set() and delete() return boolean success values:
$success = SecureStorage::set('api_key', $key);
if (!$success) {
// Handle storage failure
Log::error('Failed to store API key');
}
3. Handle Null Returns
Always check if get() returns null:
$token = SecureStorage::get('auth_token');
if ($token === null) {
// User not logged in or token expired
return redirect()->route('login');
}
4. Use Descriptive Keys
Use clear, namespaced keys to avoid collisions:
// Good
SecureStorage::set('auth.access_token', $token);
SecureStorage::set('auth.refresh_token', $refreshToken);
// Avoid
SecureStorage::set('token', $token);
5. Clear on Logout
Always remove sensitive data when users log out:
public function logout()
{
SecureStorage::delete('auth_token');
SecureStorage::delete('refresh_token');
SecureStorage::delete('user_email');
auth()->logout();
}
6. Don’t Store Large Data
Secure Storage is designed for small pieces of data (tokens, keys, passwords). Don’t store large amounts of data:
// Good
SecureStorage::set('api_token', $token);
// Bad - Use encrypted database or files instead
// SecureStorage::set('user_documents', json_encode($documents));
Security Considerations
-
Device Lock Required: On both iOS and Android, the security of Secure Storage depends on the device having a passcode/biometric lock enabled.
-
Jailbroken/Rooted Devices: Secure Storage may be compromised on jailbroken (iOS) or rooted (Android) devices.
-
Backup Considerations:
- iOS: Data may be backed up to iCloud Keychain
- Android: Data is NOT included in backups
-
No Encryption at Application Level: Don’t rely on Secure Storage alone for highly sensitive data. Consider additional encryption at the application level for critical secrets.
-
Key Rotation: Implement key rotation for long-lived tokens:
public function rotateToken()
{
$oldToken = SecureStorage::get('auth_token');
// Request new token from API
$newToken = $this->refreshToken($oldToken);
// Update stored token
SecureStorage::set('auth_token', $newToken);
}