vmux
AppsRemoteSignerPhone

Approving Signing Requests

What happens when a paired device asks for a signature, and how to approve or deny each request.

What a sign request is

Every time a paired Mac or Vision Pro begins an SSH connection that uses one of your iPhone-held keys, the SSH client on that device asks the SSH agent (vmuxAgent on Mac, the embedded vmux client on visionOS) to sign a small challenge from the server. The agent forwards that request to RemoteSignerPhone over the encrypted Multipeer Connectivity link.

The iPhone receives the request, looks up which of its identities matches the public key the server is asking about, and presents you with a Sign Request sheet. The Secure Enclave never produces a signature until you explicitly approve.

This is per-handshake, not per-session. SSH usually only signs once per connection (at handshake time) — once you're in a shell, no more signatures are needed for that session, even if it lasts for hours. Re-signing happens when you reconnect, when you start a new SSH session, when git pull makes a fresh connection, and so on.

The notification path

When a signing request arrives, two things happen at once:

  • A time-sensitive local notification is posted with title SSH Sign Request and body From <device> → <host>. iOS displays this as a banner even in Focus modes, taking advantage of the time-sensitive interruption level. Tap the banner to bring RemoteSignerPhone forward.
  • The app receives the request and queues it for approval. If the app is already in the foreground, the Sign Request sheet appears immediately.

If the app is locked behind the iOS lock screen, you'll see the notification from the lock screen and can either tap it to launch the app or unlock the phone first and let the app present the sheet directly.

What the Sign Request sheet shows

The sheet has three labeled sections:

SectionContent
From DeviceThe display name of the paired Mac or headset that initiated the request — for example, Doug's MacBook Pro or Doug's Vision Pro
DestinationThe SSH server hostname being targeted, and (if known) the SSH username
ActionTwo buttons: Approve (prominent) and Deny (destructive)

You should read both From Device and Destination before approving. The destination is the most important — it tells you what server is being authenticated to. If you initiated the connection yourself a moment ago, it should match what you typed; if it doesn't, deny.

The sheet does not show:

  • The full data that will be signed (it's an opaque SSH challenge — meaningful only to the SSH server).
  • The fingerprint of the key being used (the iPhone selects this internally based on which public key the server asked for).
  • A "remember this approval" toggle. There isn't one, by design.

Approving

Tap Approve. This triggers the iOS biometric flow:

  1. Face ID camera or Touch ID sensor activates (whichever your device supports).
  2. On a successful biometric match, the Secure Enclave produces a signature over the request payload.
  3. The iPhone sends the signature back to the requesting device over the Multipeer link.
  4. The Sign Request sheet dismisses.
  5. The Status banner on the home screen reads Approved remote sign request.

On the Mac or headset side, the SSH connection completes and you land in your shell.

If biometrics fail (face not recognized, Touch ID retries exhausted, the phone passcode is required as a fallback), iOS shows the standard fallback prompts. If you cancel the biometric prompt or fail it past the retry limit, the signing fails — the Mac or headset receives an error response and the SSH connection drops with a "permission denied" message. You can retry the connection.

Denying

Tap Deny. The iPhone sends a response to the paired device with approved: false and the error code userDenied. The Sign Request sheet dismisses. The Status banner reads Denied remote sign request.

On the Mac or headset side, ssh reports something like sign_and_send_pubkey: signing failed for ECDSA "<key>" from agent: agent refused operation, and the connection attempt fails. There is no auto-retry; if you change your mind, you have to re-initiate the connection.

Use Deny when:

  • You did not initiate this connection. Someone or something else is trying to use your key.
  • The destination host is wrong, mistyped, or unfamiliar.
  • The source device is one that should not be making this request right now (your headset is in a closet, your Mac was supposed to be off, etc.).

A denied request is logged on the Mac in vmuxAgent's request log. You can review the trail later if you want to spot-check who tried what.

What if you don't respond

The Sign Request sheet stays visible until you act on it. There is no client-side timeout enforced by RemoteSignerPhone itself — but the SSH client on the requesting Mac or headset has its own connection timeout (typically about 10 seconds for the auth phase). If you take longer than that, the SSH client gives up; when you eventually approve, the iPhone produces a signature that has nowhere to go and the Status banner notes a delivery failure.

In practice: respond within about ten seconds, or just deny and re-initiate the connection. If you genuinely cannot get to your phone in time, the cleanest recovery is to deny, ignore the resulting error on the requester, and start a new connection when you're ready.

Multiple requests in flight

If two paired devices ask for signatures within the same second, only the first one shows a sheet. The second is queued and shown after you act on the first. This is rare — humans don't normally type ssh on two devices simultaneously. It can happen if a backgrounded automation kicks in (a cron job, a periodic git pull) at the same moment you're using a connected device manually.

If a second request arrives while you're staring at the first, the home screen's Status banner will note the second request's existence; you'll see the sheet for it as soon as you approve or deny the first.

Why there is no auto-approve

This is a deliberate architectural choice, not an oversight. The whole reason to put SSH keys on the Secure Enclave is to require user presence per signature. An auto-approve mode — "trust this Mac for the next hour" — would defeat the model: a compromised Mac could silently produce signatures during the trust window, against any host the attacker chose. Per-request biometric approval is the property that makes the rest of the architecture meaningful.

If you're doing a long sequence of operations that triggers many signatures (say, deploying with Ansible), each one will prompt. You will Face ID a lot. That is the cost of cryptographic certainty about every signature your iPhone produces. If you want to reduce prompt frequency for a specific high-throughput task, the answer is to use SSH certificates: have the iPhone issue a short-lived (for example, eight-hour) certificate to the Mac once, and let the Mac use the certificate without per-handshake prompts for its lifetime. See SSH signing with iPhone for the certificate flow.

Reviewing past approvals

RemoteSignerPhone shows the most recent action in its Status banner (which auto-clears after a few seconds), but it does not currently retain a history of approvals or denials beyond that. If you want a persistent audit log:

  • vmuxAgent on the Mac keeps a log of every request it forwarded, with timestamps and decisions. See its troubleshooting page for the log location.
  • Your servers' SSH logs (/var/log/auth.log on Linux) record every successful signature with the key fingerprint. Cross-reference fingerprints from RemoteSignerPhone's identity detail screens to attribute server logins to specific iPhone identities.