Practice page

Practice a handoff.

Checking for the extension…

Right-click a sample field, choose Remote Fill, scan, and send. Nothing is submitted.

  1. 1Choose
  2. 2Scan
  3. 3Send
?
Short textThe phone should show a single-line text box.
?
PasswordThe phone should show a masked password box with its own reveal control.

Re-masks after 10 seconds or when this page loses focus.

?
Long textThe phone should show a multi-line text area.

Practice only. There is no form or submit action, and values stay on this page.

Under the hood

From right-click to filled field.

A step-by-step view of how the example value "123" moves from the phone to the selected field.

Desktop setup

No value exists.

  1. 01

    Chrome worker

    Invoke

    The user right-clicks a supported editable field and chooses Remote Fill. Chrome starts the transfer in that tab and frame.

    Transferstarted
  2. 02

    Content script

    Bind target

    Require HTTPS and a focused supported field. Record its origin, document, root, parent, ancestry, form, kind, and security-relevant attributes.

    Bindingtarget + context snapshot
  3. 03

    Content script

    Generate transaction

    Create one-time identifiers, separate read and write access secrets, a challenge, and a non-extractable ephemeral P-256 key pair.

    Private statedesktop private key stays here
  4. 04

    Worker → relay

    Reserve

    The relay reserves a short-lived, single-use mailbox using an opaque identifier, an expiry, and hashes of the separate read and write access secrets. It receives no value or destination details.

    Relay statereserved · empty
  5. 05

    Content script

    Render bootstrap

    The extension displays a QR containing the short-lived transaction details the phone needs, while keeping browser-only bootstrap data out of network requests.

    QRvisible until the first claim
  6. 06

    Worker → relay

    Subscribe

    The desktop opens one authenticated listener for claim and delivery events. It closes automatically when the reservation expires.

    Listenerone desktop

Phone claim and encryption

Plaintext remains at the endpoint.

  1. 07

    Phone → relay

    Claim

    The phone checks the transaction details and expiry, removes them from browser history, and claims the transfer. Later scans are rejected and the desktop removes the QR.

    Claimfirst phone wins
  2. 08

    Phone

    Encode value

    The user enters "123". Send encodes it as UTF-8 and clears the visible control.

    Plaintext bytes31 32 33
  3. 09

    Phone Web Crypto

    Derive key

    The phone creates an ephemeral P-256 key pair, combines it with the desktop public key through ECDH, and uses HKDF-SHA-256 to derive a unique 32-byte content key.

    Key derivationP-256 ECDH → HKDF-SHA-256 → content key
  4. 10

    Phone Web Crypto

    Encrypt

    AES-256-GCM encrypts the bytes with a fresh nonce and authenticates the transfer's destination, field type, and expiry. The plaintext buffer is cleared.

    Result3-byte ciphertext + 16-byte tag
  5. 11

    Phone → relay

    Upload

    The phone sends an encrypted package containing its public key, nonce, and ciphertext, together with the credentials for the claimed transfer. The relay checks authority, size, and shape, then marks the package ready for one delivery.

    Packageopaque authenticated envelope

Delivery and insertion

Only the endpoints can recover the value.

  1. 12

    Relay → worker

    Deliver once

    The relay sends the encrypted package once and removes it. If the desktop is not yet listening, ciphertext waits only until the listener connects or the transfer expires.

    Deliveryone delivery or expiry
  2. 13

    Content script

    Authenticate and decrypt

    The worker validates and returns the bounded envelope. The content script repeats ECDH and HKDF; AES-GCM releases the bytes only if the ciphertext and full transfer context authenticate.

    Output31 32 33 → "123"
  3. 14

    Content script → field

    Revalidate and fill

    The extension confirms that the original field and its page context are unchanged, fills it through browser-native input behavior, and clears plaintext. It never submits.

    Final stateselected field = "123"