Skip to content

Proposal: game-scoped session signer — promptless host signing as a user-scoped identity (//candidate) #274

Description

@peetzweg

Pre-RFC / discussion-opener from the DIM2 (Jollity) web product team. Full write-up (with alternatives, security, migration, and the long-run direction): https://github.com/paritytech/dim2-spa-fable/blob/main/docs/proposals/game-scoped-session-signer.md — issue refs like #23/#16/#26 below are in the dim2-spa-fable repo.

The gap

DIM2 runs sandboxed under the Host API and follows the no-keys model (product addresses accounts, host holds keys). But the Game pallet requires the statement signer to BE the registered player — the //candidate account (a hard derivation of the user's root), which sign-up registers and grants a PlayerStatementLimit statement-store allowance.

//candidate (sr25519) must sign on two surfaces during a game:

  • Statements — the signaling stream (high-frequency): every SDP offer/answer, each ICE candidate, and the request/ACK handshake is a statement whose proof is signed by //candidatedozens per minute, continuously. Must be promptless.
  • Extrinsics (a handful/game): Game.report at end (in the web product, mid-session), plus sign_up (can be native/phone) and occasional offboard.

What hosts offer today doesn't fit — the gap is which identity signs, not whether the host can sign promptlessly:

  • create_proof_authorized (RFC-0010): promptless, but signs with the host's session/allowance account — not //candidate, and it has no PlayerStatementLimit allowance, so the Game pallet rejects it.
  • Product accounts: soft-derived, product-scoped; the runtime doesn't recognize them as players.
  • sign_payload / create_transaction: per-signature confirmation — fine for ~2 extrinsics, unusable for a signaling stream.
  • Entropy.derive (RFC-0007): derived bytes for product-held keys — the opposite of what's needed.

The product must never see key material, so there's no product-side workaround that isn't a custody regression.

The ask (one new capability)

A session-scoped, promptless signer bound to a specific user-scoped, host-owned derivation, under an explicit bounded scope:

open_scoped_session({
  identity: Derivation("pop-candidate") | IdentityRef([u8;32]),  // which host-owned key
  scope: {
    statements: { topics, channels, max_per_minute },           // promptless within scope
    calls: ["Game.report"],                                      // tiny extrinsic allowlist
    expires_at,
  },
}) -> { session_id, public_key }
// then: session_sign_statement / session_create_transaction (promptless, in-scope only)
//       close_scoped_session (visible + revocable)

One consent sheet at open; everything in-scope then promptless; out-of-scope is a typed error, never a silent fallback. Framed as a generalization of create_proof_authorized/RFC-0010 along the identity axis — not a new signing engine. Mobile hosts already do exactly this natively (the native game signs statements + report with //candidate); this exposes existing behavior as a wire capability so hosted web/desktop products reach parity.

Long-run context (opens a second discussion)

This is deliberately the identity primitive. Orthogonally, we think the transport should eventually become a host primitive too — connect(peer) → media tracks + native call UI, never touching WebRTC (the ext.media direction). The two compose: even a fully host-owned connection would still need to sign DIM2's signaling as //candidate, because those statements are the on-chain player record. Generic 1:1 calling apps would use only the connection primitive; personhood/on-chain apps like DIM2 use both. Tracked separately (dim2-spa-fable#26); the ext.media blocker for us is a product-facing data channel + an identity hook (this proposal's IdentitySelector).

Open questions for the host-sdk / truapi team

  1. Identity selector: RFC-vetted named-derivation registry vs opaque identity_ref minted by a prior host flow (e.g. native sign-up)?
  2. Home: new trait, extension of Signing, or a new RFC-0010 allowance kind under ResourceAllocation?
  3. dotli cross-device: the keystore is the paired phone — does the phone hold the session (relay latency per statement?) or delegate a session key to the web host for the scope?
  4. Statement-scope vocabulary: topics/channels, or reference the on-chain PlayerStatementLimit?
  5. Consent copy ownership: host heuristics vs RFC-registered use-case strings?
  6. Contract of record: truapi RFC first, or prototype as a useragent-kit/host-container extension and graduate?

Happy to prototype the product side against @parity/host-api-test-sdk and be the first consumer — our M5 is blocked on the direction chosen here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions