Skip to content

Compose lifecycle and UI state

PasskeyFlow does not own product state; it keeps only a per-instance concurrency guard. The application owns presentation state, navigation, retry policy, session state, and messages. Compose helpers remember the client and flow; they do not replace a product state model.

State Owner Lifetime
PasskeyClient and PasskeyFlow Stable feature/composition boundary While its host context remains valid
Current PasskeyPhase Screen or view model One active ceremony
Form input and visible error Product UI state Screen policy
Backend session/account Application session layer Product session
Raw credential response Ephemeral flow value Until finish completes
PRF-derived session key Explicit crypto session Shortest practical lifetime

Concurrency

One flow instance permits one active ceremony. A second call returns CeremonyFailure.AlreadyInProgress; it is not queued. Disable registration and sign-in actions while active, and still handle that typed outcome because UI events can race.

Phase callbacks

The callback reports STARTING, PLATFORM_PROMPT, and FINISHING. It is synchronous and application-owned. Keep it fast, do not perform blocking work, and do not throw unless you intend to abort and handle the exception at your boundary.

Cancellation and host changes

Let coroutine cancellation propagate. Android Activity recreation, iOS scene changes, navigation, and application backgrounding can invalidate UI hosts. Construct or resolve presentation objects at a lifecycle that matches the platform bridge rather than storing a stale host globally.

Preview and testing layers

Use fake state for previews, fake PasskeyClient/backend implementations for common orchestration tests, platform host tests for mapping and lifecycle behavior, and provider-backed devices for the actual prompt. A preview must not initialize networking, dependency injection, or platform credential APIs.