Skip to content

x402 phase 1: sign-in-with-x — the agent authenticates for free, nothing at risk #32

Description

@hellno

Why

Agents need to authenticate to HTTP services. x402 (Linux Foundation) specs this as the sign-in-with-x extension: the server's 402 response advertises it, the client signs a CAIP-122/SIWE challenge (eip191 for EOAs) and retries with a SIGN-IN-WITH-X header — zero value at risk, no chain interaction, replay-protected by the server nonce.

Canonical extension spec: https://github.com/x402-foundation/x402/blob/main/specs/extensions/sign-in-with-x.md (signature types eip191/eip1271/eip6492; auth is an extension, not a zero-amount payment).

Corrected 2026-07-10 (codebase re-verified): this issue's original premise — "this is the FIRST message-signing path; the seam lands before payments so parse→policy→card→sign exists with nothing at stake" — is stale. That seam already shipped. So does the general personal_sign path this issue said to "permanently exclude". #32 is still net-new product, but it is NOT a prerequisite for #34, and NOT on the $5/day critical path. Corrections below.

Already shipped (the seam exists — verified 2026-07-10)

Via #133/#155, on main:

  • SignerRequest::ProposeMessage / SignMessage wire + SignMessageKind (PersonalSign | TypedDataV4 | EthSign | Authorization7702) in message_signing.rs.
  • evaluate_message policy path (policy.rs:861).
  • Daemon handlers propose_message / sign_message (daemon.rs:875, :366-372).
  • The clear-signing card renders messages (activity_view.rs:1299-1437).

Two consequences for this issue:

  1. The "build the message-signing seam first, nothing at stake" ordering vs x402 phase 2: exact/EIP-3009 payments on the Ethereum reference path, fully local demo loop #34 is already satisfiedx402 phase 1: sign-in-with-x — the agent authenticates for free, nothing at risk #32 does not block x402 phase 2: exact/EIP-3009 payments on the Ethereum reference path, fully local demo loop #34.
  2. The claim to "permanently exclude raw personal_sign of arbitrary bytes" is contradictedSignMessageKind::PersonalSign { message: Bytes } already exists and evaluate_message returns NeedsApproval for it. Reconcile this stance in-issue before building. (Note: no MCP tool exposes any message path to agents today — the agent surface is still net-new.)

In scope (the actual net-new work)

  • SignIn { domain, challenge: SiweFields } request in deckard-contract under capability name sign-in-with-x (additive per Wire-contract evolution: Hello capability discovery + the five evolution rules #31's evolution rules; capabilities.rs extension point is ready).
  • Daemon: CAIP-122/EIP-4361 parse → re-serialize → eip191 sign; malformed/unparseable challenge → typed Deny, nothing signed. (Reuses the existing message evaluate/card seam.)
  • Policy: domain_allow: Vec<String>; existing ApprovalMode semantics apply; mainnet guardrail unchanged (on chain 1, auto-Allow downgrades to NeedsApproval).
  • MCP tool deckard_x402_sign_in — the first agent-facing message tool — registered only when the daemon advertises the capability.
  • Acceptance: X1 sign-in to an allowlisted domain → HTTP 200, zero value moved, clean transcript; X2 domain ∉ domain_allow → typed Deny; X10 transcript scan → no key bytes / passphrase / bearer tokens.

Not in scope

Sequencing

Off the $5/day critical path (#34#208#209 do not depend on #32). A "nothing at risk" warm-up. Since the message seam already exists, the remaining SIWE parse + capability + domain_allow + MCP tool is smaller than the original body implied — run it in parallel off the same foundations if there's spare capacity; skip it if focused on the demo.

Definition of done

  • All net-new in-scope items; new Deny reasons from the frozen vocabulary (Freeze the Deny-reason vocabulary in deckard-contract #28).
  • cargo fmt --all --check clean; just check green (both feature configs); cargo test --workspace green.
  • Any new dep (SIWE parsing may be hand-rolled — the grammar is small) listed and approved before merge.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions