UC-005: Unlock Wallet with Biometrics
Description
The user unlocks the wallet using biometric authentication (Touch ID / Face ID) after the session has been locked due to inactivity. This provides a faster alternative to password entry. The biometric unlock is available on two screens: the in-app lock screen overlay and the dedicated unlock page. Password entry is always available as a fallback.
Actors
- End User: Person unlocking the wallet with biometrics
- Wallet (Frontend): Svelte application managing the lock screen UI and session state
- Wallet (Rust Backend): Tauri commands interfacing with the OS biometric APIs
- Operating System: Provides the biometric authentication prompt
Preconditions
- The user has an identity created in the wallet
- Biometric authentication has been enabled (UC-004) —
biometricEnabled: truein the Tauri Store - The wallet session is locked (due to inactivity timeout or manual lock)
- The device has biometric hardware available and functional
Main Flow
- The wallet session locks (inactivity timeout or manual lock action)
- The lock screen is displayed (either
LockScreen.svelteoverlay or/unlockpage) - The lock screen checks biometric availability: invokes
is_biometric_available - Both conditions are met (
biometricEnabled && biometricAvailable), so the Use Biometric button is rendered alongside the password input - The user clicks Use Biometric
- The wallet invokes the Rust command
authenticate_biometric - The OS displays the native biometric prompt (Touch ID dialog on macOS)
- The user authenticates successfully (fingerprint or face)
- The Rust backend returns success
- The wallet calls
unlockSession()to restore the unlocked state - The user is returned to the dashboard
Alternative Flows
AF-1: Biometric verification fails
- At step 8, the biometric does not match
- The lock screen shows an error message: "Biometric authentication failed"
- The user remains on the lock screen and can retry biometrics or use the password
AF-2: User cancels biometric prompt
- At step 8, the user cancels the OS dialog
- No error is shown (cancellation is silently handled)
- The user remains on the lock screen and can retry or use the password
AF-3: Biometric hardware unavailable at unlock time
- At step 3,
is_biometric_availablereturnsfalse(hardware disconnected, driver issue, etc.) - The Use Biometric button is not shown
- Only password entry is available
AF-4: User chooses password instead
- At step 5, the user types their password in the password field instead of clicking the biometric button
- The wallet verifies the password hash via Argon2
- If valid, the session unlocks normally
AF-5: Unlock via dedicated page
- The wallet navigates to
/unlockinstead of showing the lock screen overlay - The flow is identical: biometric button shown if conditions met, on success navigates to
/dashboard
Postconditions
- The wallet session is unlocked
- The user has access to the dashboard and all wallet features
- No persistent state changes occur — biometric unlock is stateless
- The inactivity timer resets
Modules Involved
| Module | Role |
|---|---|
| wallet (frontend) | Lock screen UI (LockScreen.svelte and /unlock), biometric button rendering, session unlock |
| wallet (Rust backend) | authenticate_biometric command via macOS LAContext |
Technical Notes
- Two unlock screens:
LockScreen.svelteis an in-app overlay component;/unlockis a dedicated route page. Both implement the same biometric flow independently - Stateless authentication: Each biometric unlock is a fresh OS-level verification. No tokens, sessions, or cached results are reused
- Password always available: The password input is always rendered regardless of biometric availability, ensuring the user is never locked out
- No biometric data flows through the wallet: The Rust backend asks the OS to verify, receives a boolean result, and never accesses raw biometric data
- Condition for biometric button:
biometricEnabled(user preference from store) ANDbiometricAvailable(live hardware check). Both must betrue