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

Preparing connection metadata…

The entries below are test wallet accounts, not registered identities.

Loading wallet accounts…

2. Test an identity action

Provider consent uses the configured live clients. X and Google use their real proof boundaries; GitHub still uses the ceremony module's fake backend exchange. Register https://backend.libid-poc.dyaka.global/oauth/callback for all three.

Starting broker…
Prover mode · detecting browser capability…
Provider launch · detecting input capability…
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; expect the requested 480×720 provider popup, record any browser setting that promotes it to a 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

  1. Verify Application is this app origin, Callback entry is https://backend.libid-poc.dyaka.global/oauth/callback, and Redirect asset is https://wallet.libid-poc.dyaka.global. There must be no /oauth/prepare request. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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. The normal path must keep one popup from /prepare-key through provider consent, the backend redirect, and wallet confirmation.
  7. Open ?relayLab=1 to test the COOP-resistant ceremony transport. The app and callback backend must be sibling HTTPS origins under one registrable domain; cross-site deployments are intentionally unsupported. A hidden backend iframe stores a short-lived, host-only capability before OAuth; fresh WebRTC SDP is exchanged through cookies only after the callback. Credentials, progress, and proof stay off cookies and move over direct WebRTC. Verify the callback reports opener === null. Add &relayCookieLoss=1 to delete the one-use capability and verify a restart message.
  8. 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.
  9. 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.
  10. 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.
  11. Verify X, Google, GitHub, retries, and two simultaneous actions. Chromium should prove in an isolated backend-origin DIP iframe inside the redirect. Firefox/WebKit must expose a native Continue proving link that opens one temporary isolated backend-origin prover per action, closes it after checkpointing, and returns to the original redirect popup.
  12. With DevTools open, verify the app, wallet broker, and popup remain non-isolated while https://backend.libid-poc.dyaka.global/api/v1/ceremony/prover is cross-origin isolated with SharedArrayBuffer. Record backend-iframe or backend-popup, and verify substantial JS/WASM assets come only from https://wallet.libid-poc.dyaka.global.
  13. Verify the app owns the durable job and proof-ready checkpoint, wallet storage holds the pending non-extractable key and later the confirmed action, and broker RAM is disposable. Reload the app after proof readiness, then register: the wallet must authenticate the action with its persisted return capability, the app must verify and persist the signed envelope, ACK it, and the popup must close. No /api/status request may occur.
  14. 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.
  15. Delete/reload the broker before consent and again before registration. Because the ceremony keeps OAuth credentials and proving input in memory, destroying its callback or prover before proof delivery must require fresh OAuth. Reload after proof delivery must recover the app-owned proof-ready checkpoint without proving again.
  16. 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 /api/v1/ceremony/prover artifact used for proving. Concurrent actions must join the same in-flight fetch, and the DIP and popup fallback 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 backend popup/prover origin and record the warning plus both times.
  17. Start X and Google before either finishes. Both must remain visible with independent cancellation. Chromium uses a backend-origin DIP per redirect popup; Firefox/WebKit require one native-link click and one auxiliary prover per action. Cancel one while the other completes.
  18. Background the wallet after proof completion. A badge or notification is a best-effort convenience only: record it if offered, but recovery through the action list must work without it.
  19. 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.
  20. 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.
  21. 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.
  22. 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.
  23. 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.