Skip to main content

Session Storage

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

Why Keychain?

Session data includes sensitive cryptographic keys. Keychain provides:
  • Hardware-backed encryption
  • Access control (biometrics, passcode)
  • Secure enclave support
  • Data protection across app updates
There are two ways to use it. The SDK can own the vault in the Keychain itself through a KeychainDelegate, which is the path described next, or the app can export the session and store it with its own Keychain code, which the rest of this guide covers.

SDK-Managed Persistence

Select persistenceStorage: .osKeychain and an unlock method, and register a KeychainDelegate before constructing the SDK. PrivacyBoost.withPlatformDefaults(config:) from the PrivacyBoostDefaults product registers DefaultKeychainDelegate() for you unless the app already registered its own, then constructs the SDK:
DefaultKeychainDelegate stores items as generic passwords under one service name (com.privacyboost.sdk unless you pass another to its initializer) with kSecAttrAccessibleWhenUnlockedThisDeviceOnly. To use your own Keychain code instead, conform to KeychainDelegate and register it yourself:
registerKeychainDelegate takes an optional service: that namespaces the vault items. Omit it and the SDK uses its own name, which is what a single-SDK app wants; pass your own (a bundle id, say) when two SDK instances or an app extension share the process or a Keychain group, so their items cannot collide. The registration is process-wide: do it once, before the first PrivacyBoost whose config selects .osKeychain, 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. .localStorage and .indexedDb are browser backends and are rejected on iOS, as is .passkey unlock.

Unlock methods

Unlocking on the next launch

With .pin or .password, the first launch returns .credentialRequired with challenge.action == .setup, where the user chooses the credential, and every later launch returns it with challenge.action == .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.

Basic Keychain Wrapper

Create a Keychain helper:

Session Storage

Store and retrieve Privacy Boost sessions:

Biometric Protection

Add Face ID/Touch ID protection:

Usage in App

Integrate with your SDK manager:

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.
nil or 0 disables the respective timer, and both default to nil. 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 kSecAttrAccessibleWhenUnlockedThisDeviceOnly - Data only accessible when device is unlocked
  2. Enable biometrics - Add Face ID/Touch ID for sensitive operations
  3. Don’t store in UserDefaults - UserDefaults is not encrypted
  4. Clear on logout - Delete Keychain items when user logs out
  5. Handle errors gracefully - Don’t expose Keychain errors to users

Info.plist

Add Face ID usage description:

Next Steps