Embedding application
Mobile popup UX PoC
The wallet owns keys and confirmation; the ceremony module owns OAuth and proving. This page never receives a credential or key.
1. Choose a wallet
The entries below are test wallet accounts, not registered identities.
2. Test an identity action
OAuth and proving run through the rebuilt ceremony package. Register https://backend.libid-poc.dyaka.global/auth/callback with the provider. This wallet PoC signs a local composition envelope; it does not establish ledger verification.
Manual test checklist
Choose your device row
- iPhone/iPad: Safari with popup blocking on and off, Chrome, Home Screen mode, and each supported in-app browser. Expect the two-argument auxiliary launch to use Safari's normal new-tab/page presentation; WebKit emulation does not qualify the physical device.
- Android: Chrome, WebView, and each supported in-app browser, with provider apps installed and absent. Expect provider consent in the browser's normal new-tab/page presentation and record the displayed prover mode rather than inferring support from the browser name.
- Desktop: real Chrome, Firefox, and Safari; record whether the browser presents the default auxiliary page as a window or tab, and test popup allow/block and keyboard activation.
Open auto-presentation risk: this PoC treats (hover: hover) and (pointer: fine) as desktop-like and requests a compact popup; otherwise it uses the browser-default auxiliary page. This is an input-capability heuristic, not reliable mobile detection: an iPad with a trackpad, touch laptop, desktop-mode browser, or changed peripherals may choose an unexpected presentation. Record both the displayed policy and what the browser actually opens. No production selection API is proposed yet: making the mode configurable would merely move the unresolved classification problem to integrators. Revisit the policy only if real-device testing confirms a failure and provides a concrete condition worth supporting.
Run on every row
- Verify Application is this app origin, Callback entry is
https://backend.libid-poc.dyaka.global/oauth/callback, and Redirect asset ishttps://wallet.libid-poc.dyaka.global. There must be no/oauth/preparerequest. The redirect must clear the provider response before loading external code, then authorize the live opener origin and its configured client ID. No credential may reach the app origin. - Use Reset wallet state. The app must automatically visit the wallet origin and return without a Connect click or another tab. Both test wallets must say No registered identities, and every provider must remain disabled until one visibly selected wallet is chosen.
- Reload after connecting. The app must repeat the automatic top-level wallet-origin visit every time rather than treating any iframe storage read as authoritative. Confirm that reset makes the following visit rebuild the wallet state, and that Back reveals neither the wallet bootstrap,
about:blank, nor another synchronization loop. - Do not infer storage partitioning from the Chromium, Firefox, or WebKit label in automated results. Playwright exercises the flow, but only the shipping browser and its privacy defaults qualify storage behavior.
- Register one provider with test wallet A and another with wallet B. Reload between actions and verify each identity remains attached only to the selected wallet.
- Use live consent for all three providers: approve, deny, close the consent popup, register, reject, reload, screen lock, portrait/landscape, zoomed text, and dark mode. X and Google exercise their real proof boundaries; GitHub currently qualifies popup/wallet composition around a fake backend exchange only. One popup and one logical connection run from
/prepare-keythrough provider consent, isolated proving, wallet confirmation, and signed-envelope delivery. - A plain action must pass directly from the app gesture to provider consent, with no wallet pre-consent click. A protected cache miss may still require Unlock and continue; cancellation leaves the integration unseen.
- After confirmed registration, a protected cache miss shows Unlock and continue. A same-app/same-chain cache hit skips unlock but never skips final confirmation. Reload app A and expect the RAM unlock cache to be gone.
- For a protected pending key, verify confirmation performs one fresh WebAuthn operation after proving. Canceling or expiring the action must leave no reusable key or resumable job.
- Verify X, Google, GitHub, retries, and two simultaneous actions. Every engine must keep one ceremony popup: Prefetch warms the selected profile, Callback privately navigates to Prover, and the popup layer preserves the MessagePort through the CCDP Worker when an isolation fallback is needed.
- With DevTools open, verify the app, wallet broker, and provider return remain non-isolated while the CCDP Prover is cross-origin isolated with
SharedArrayBuffer. There must be no post-callback iframe or second prover popup; substantial JS/WASM assets must come only fromhttps://wallet.libid-poc.dyaka.global. - Close the provider consent window before it returns. The public app job must require a fresh authorization; Cancel must remove the old job and pending wallet key. A provider redirect containing an explicit denial must cancel immediately.
- Run the required four-thread real UltraHonk prover for X. Record every displayed stage, proof duration, any Safari memory warning/reload, and whether Cancel stops it. Compare a cold private profile with a second run in the same profile, including 1.5-second asset latency, and record Prefetch, Static fetch, and CRS fetch. The initial popup automatically warms the exact compressed G1 range + 4 MiB Grumpkin + 128-byte G2 data used by this circuit through the same
/ccdp/v1/proverartifact used for proving. Concurrent actions must join the same in-flight fetch, and the isolated top-level Prover must reuse that cache without downloading the ranges again. A warmup failure may make the same profile cold but must never select one thread or an unisolated prover. On Vanadium compare JavaScript JIT off/on for the wallet CCDP origin and record the warning plus both times. - Start X and Google before either finishes. Both must remain visible with an independent popup, PortKeeper entry, CCDP carrier, and cancellation path. Cancel one while the other completes.
- Repeat from an app served with no COOP and with
same-origin-allow-popups; both should work. Strict COOP+COEP must fail before provider launch, while COOP without COEP must fail at redirect authentication because the opener was severed. - Complete X and cancel Google in provider popups. Background, lock, rotate, back-swipe, and switch apps while proving. On physical iOS, record any Safari reload or memory error; WebKit emulation does not reproduce the iOS memory ceiling.
- For X, Google, and GitHub, repeat with: app signed in/browser signed out; app signed out/browser signed in; app absent/browser signed in; both signed out.
- Approve and deny, background during OAuth, and override browser/app preferences. Verify the provider returns the same popup. Treat a provider-created replacement tab as an expected fail-closed result until a separately authenticated app-origin bridge is designed.
- If launch or close is refused, verify Retry/Open in browser guidance, then confirm the app eventually shows one terminal result.
Expected on iOS: browser OAuth for all three providers. Android may offer X or GitHub; Google is expected to remain in the browser. Use dedicated test accounts in in-app browsers and remove the “WebWallet mobile UX PoC” passkey after qualification.