FIDO2 Touch Prompt UI (Issue #2631)
Feasibility explored, not yet scheduled. FIDO2 / WebAuthn support is an opt-in beta behind auth.webauthn.enabled (see ADR-021).
Date: 2026-06-09 Issue: #2631 - FIDO2: missing UI prompt when waiting for authenticator touch Status: Research / feasibility (treated as an enhancement, not a regression)
Summary
#2631 reports that while the authenticator waits for a physical touch (the user-presence check), Teams for Linux shows no on-screen prompt, so the app appears frozen. This is a missing-UX gap in the opt-in FIDO2 beta, not a regression: authentication completes correctly if the user knows to touch the key. Adding a "touch your security key now" prompt is feasible and low-risk, with one honest limitation, namely that we can show the prompt for the duration of the security-key call but cannot pinpoint the exact instant the key starts waiting for touch.
Current behaviour
A security-key assertion from the Microsoft login page flows through:
app/browser/tools/webauthnOverride.jscallsipcRenderer.invoke("webauthn:get", …).app/webauthn/index.js:80handleWebauthnRequest: whenuserVerification === "required", the PIN is collected up front viaapp/webauthn/pinDialog.js. This PIN dialog is the only UI the flow ever shows.app/webauthn/index.js:114-115callsfido2Backend.getAssertion/createCredential.app/webauthn/fido2Backend.js:45spawnsfido2-assert/fido2-cred. After the PIN is written to stdin (fido2Backend.js:76), the child process performs the user-presence check and blocks until the key is physically touched. Theawaitdoes not resolve untilproc.on("close")(fido2Backend.js:80).
During that touch wait the PIN dialog has already closed and no other window is shown. A search confirms there is no touch / user-presence UI anywhere in app/webauthn/.
Why this is a feature request, not a bug
The FIDO2 beta (PR #2357, ADR-021) deliberately scoped its UI to PIN entry. A touch prompt was never built. Nothing broke; the flow works for a user who knows to touch the key. The honest framing is a missing-UX polish step in an opt-in beta.
Feasibility and approach
Feasible and low-risk. The cleanest insertion point is handleWebauthnRequest in app/webauthn/index.js, wrapping the backend call at lines 114-115: show a non-blocking, frameless BrowserWindow (or a Notification) immediately before the await, and dismiss it in a finally once the promise settles, whether on success, error, or the existing 60s timeout (fido2Backend.js:54). This reuses the BrowserWindow pattern already proven in pinDialog.js, so no new infrastructure is needed, and because the backend already resolves or rejects on completion and timeout, dismiss-on-completion is essentially free.
The one limitation we should not over-promise
fido2-assert / fido2-cred emit the Enter PIN for text to stderr (fido2Backend.js:72) but emit nothing at the user-presence step, so the touch wait is silent at the CLI boundary. We can reliably show a prompt that spans the security-key call (or starts right after the PIN is written, or when the process spawns for no-PIN flows), but we cannot fire it at the precise moment the key's LED starts blinking. The realistic deliverable is a generic "waiting for your security key, touch it now" prompt, not a touch-instant signal. Localised libfido2 builds also translate the stderr text (an ADR-021 known limitation), a further reason to avoid stderr-driven precision and prefer wrapping the whole call.
Risks
- Cancellation: a "Cancel" button would have to replicate the detached-process-group kill already used on timeout (
fido2Backend.js:59) and reject cleanly, or it risks orphaning thefido2child. The simplest first cut is an informational prompt with no cancel, auto-dismissed on completion or timeout. - Seamlessness: the PIN dialog closes before the touch wait, so the new prompt should appear without a visible gap.
- Window lifecycle: the
finallythat dismisses the prompt should checkisDestroyed()first, since the parent window could be closed during the wait (up to the 60s timeout) and dismissing an already-destroyed window would throw. - Scope: Linux-only, behind
auth.webauthn.enabled, beta.
Recommendation
Worth doing as a small enhancement. Reframe the ticket from bug to enhancement, set expectations to a call-duration prompt rather than touch-instant, and treat it as the next polish step after the PIN-entry UI the beta already shipped. A focused spike on the BrowserWindow-around-the-await approach, with no cancel in v1, is the lowest-risk path.