Skip to main content

Session Storage

This guide covers securely storing and restoring Privacy Boost sessions using Android Keystore, expanding on the persistence options in Key Management.

Why Keystore?

Session data includes sensitive cryptographic keys. Android Keystore provides:
  • Hardware-backed encryption (TEE/Secure Element)
  • Key material never leaves secure hardware
  • Biometric authentication support
  • Protection against extraction
There are two ways to use it. The SDK can own the vault in Keystore-backed storage itself through a KeychainDelegate, which is the path described next, or the app can export the session and store it with its own code, which the rest of this guide covers.

SDK-Managed Persistence

Select persistenceStorage = StorageBackend.OS_KEYCHAIN and an unlock method, and register a KeychainDelegate before constructing the SDK. PrivacyBoostDefaults.create(context, config) registers DefaultKeystoreDelegate(context) for you unless the app already registered its own, then constructs the SDK:
DefaultKeystoreDelegate stores entries in EncryptedSharedPreferences (privacyboost_vault unless you pass another preferenceName) under an Android Keystore master key. To use your own implementation instead, implement KeychainDelegate and register it yourself:
registerKeychainDelegate takes an optional service that namespaces the vault items. Omit it and the SDK uses its own name; pass your own when two SDK instances share the process, so their items cannot collide. The registration is process-wide: do it once, before the first PrivacyBoost whose config selects OS_KEYCHAIN, and note that a later call replaces the delegate for every instance. Construction throws SDKError.ConfigError naming register_keychain_delegate when no delegate is registered; hasKeychainDelegate() tells you whether one is. LOCAL_STORAGE and INDEXED_DB are browser backends and are rejected on Android, as is PASSKEY unlock.

Unlock methods

DefaultKeystoreDelegate does not show a biometric prompt itself. With BIOMETRIC, complete your own class-3 BiometricPrompt immediately before authenticate, on the first launch as well as later ones: the gated store stays reachable for authValiditySeconds (30 by default) after a successful prompt, and outside that window the delegate throws rather than returning nothing.

Unlocking on the next launch

With PIN or PASSWORD, the first launch returns CredentialRequired with challenge.action == CredentialAction.SETUP, where the user chooses the credential, and every later launch returns it with CredentialAction.UNLOCK. submitCredential completes the login either way and can be retried after a wrong credential without calling authenticate again:
The vault survives logout() and lock(); call deleteVault() to erase it, for example when the user removes the account from the device. Auto-lock below wipes the decrypted keys on a timer and sends the user through this same unlock on the next key access.

EncryptedSharedPreferences

The simplest approach using AndroidX Security:

Setup

Add dependency:

Implementation

Biometric Authentication

Add biometric protection for session access:

Setup

Add dependencies:

BiometricSessionStorage

Usage in Repository

ViewModel Integration

Auto-lock

Persisting a session keeps the encrypted vault on disk; auto-lock bounds how long the decrypted keys stay in memory. Two optional PrivacyBoostConfig fields drive it, both in seconds:
  • idleTtlSecs: how long the keys may go unused before the SDK wipes them.
  • absoluteTtlSecs: how long after an unlock the SDK wipes them, regardless of activity.
null or 0u disables the respective timer, and both default to null. The timers are checked lazily, on the next key access: once one has elapsed, that access zeroizes the resident keys and throws SDKError.NotAuthenticated. They bound key use rather than key residency, so a screen that needs the keys gone at a fixed time should call lock() from its own timer.
lock() does the same on demand. It zeroizes the key material and drops the session JWT but keeps the persisted vault, which makes it the right call when the app moves to the background:
To unlock, call authenticate again. With a persisted vault the SDK reopens it instead of re-deriving keys: PIN and password vaults return CredentialRequired, and the other unlock methods complete inside authenticate. Compare clearSession(), which drops the JWT but leaves the keys in memory for a quick re-auth, and logout(), which ends the session entirely. Chain-context handles created with createChainContext share the resident keys, so auto-lock and lock() apply to them too, but each keeps its own JWT; call clearSession() on the handle to drop it.

Security Best Practices

  1. Use BIOMETRIC_STRONG - Requires Class 3 biometrics
  2. Set invalidatedByBiometricEnrollment - Invalidate key if new biometric enrolled
  3. No timeout - Require auth every time for sensitive data
  4. Handle key invalidation - Clear session if key is invalidated
  5. Don’t store unencrypted - Always encrypt sensitive data

Next Steps