You've got secrets to keep. API tokens. Refresh tokens. Encryption keys.
Stuff that absolutely cannot live in plain text.
On iOS, there's the Keychain. On Android, there's the Keystore. Both are hardware-backed, encrypted by the OS.
NativePHP gives you one API for both.
In this post:
#The Basics
#PHP (Livewire)
Copied!
use Native\Mobile\Facades\SecureStorage; // Store a secretSecureStorage::set('api_token', 'sk_live_abc123xyz'); // Retrieve it$token = SecureStorage::get('api_token'); // Delete itSecureStorage::delete('api_token');
#JavaScript (Vue/React/Inertia)
Copied!
import { SecureStorage } from '@nativephp/mobile'; // Store a secretawait SecureStorage.set('api_token', 'sk_live_abc123xyz'); // Retrieve itconst { value } = await SecureStorage.get('api_token'); // Delete itawait SecureStorage.delete('api_token');
That's it. The value is encrypted by the OS using hardware-backed security.
#Storing and Retrieving
#PHP (Livewire)
Copied!
// Store credentialsSecureStorage::set('credentials', json_encode([ 'username' => $username, 'refresh_token' => $refreshToken,])); // Retrieve with null check$token = SecureStorage::get('auth_token');if ($token === null) { return redirect('/login');} // Clean up on logoutpublic function logout(){ SecureStorage::delete('auth_token'); SecureStorage::delete('refresh_token'); auth()->logout();}
#JavaScript (Vue/React/Inertia)
Copied!
import { SecureStorage } from '@nativephp/mobile'; // Store credentialsawait SecureStorage.set('credentials', JSON.stringify({ username, refreshToken})); // Retrieve with null checkconst { value } = await SecureStorage.get('auth_token');if (!token) { router.push('/login');} // Clean up on logoutconst logout = async () => { await SecureStorage.delete('auth_token'); await SecureStorage.delete('refresh_token');};
#Best Practices
#1. Use Descriptive Keys
Copied!
// BadSecureStorage::set('t', $token); // GoodSecureStorage::set('stripe_api_key', $key);
#2. Clean Up on Logout
Copied!
$keysToDelete = ['access_token', 'refresh_token', 'api_key']; foreach ($keysToDelete as $key) { SecureStorage::delete($key);}
#3. What to Store (and What Not To)
DO Store:
- Authentication tokens
- API keys
- Encryption keys
- OAuth secrets
DON'T Store:
- Large data (Keychain isn't a database)
- Non-sensitive preferences
- Frequently accessed data (has overhead)
#4. Combine with Biometrics
Copied!
// PHPpublic function viewSecrets(){ Biometrics::prompt()->id('vault-unlock');} #[On('native:' . Completed::class)]public function handleAuth(bool $success, string $id){ if ($id === 'vault-unlock' && $success) { $this->secrets = SecureStorage::get('secrets'); }}
Copied!
// JavaScriptimport { Biometric, SecureStorage, On, Off, Events } from '@nativephp/mobile'; const viewSecrets = async () => { await Biometric.prompt().id('vault-unlock');}; On(Events.Biometrics.Completed, async ({ success, id }) => { if (id === 'vault-unlock' && success) { const { value } = await SecureStorage.get('secrets'); secrets.value = value; }});
Your app now has a proper vault. Use it for everything that matters.
Stay secure. 🔒