Proof #3 now supports the production asymmetric path, not just the dev shared secret.
- context-attestation.ts: PublicKeyResolverPort seam; verify() picks ES256 (JWKS by
kid) when the client has a jwksUri, else HS256 (dev). signDevAttestationES256 helper.
- attestation-stores.ts: JwksPublicKeyResolver (jwks-rsa, one cached client per URI,
refetch on rotation, fail-closed to NO_KEY).
- attestation.module.ts: inject the resolver into the verifier; dev-seed the client as
clientType APPSHELL (it is the CRM browser-flow parent per the July-12 notes).
- rename the registered client crm-support-widget -> appshell-crm (the name reflects the
attesting parent, not a widget).
- specs: ES256 (valid via JWKS, wrong key -> BAD_SIGNATURE, unknown kid -> NO_KEY, no
resolver -> NO_KEY) + two stolen-token gate cases (wrong app binding -> APP_MISMATCH,
wrong audience -> WRONG_AUDIENCE).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A valid actor token is no longer enough. This adds the trust-layer core so IIOS
can require a signed CONTEXT ATTESTATION from an authorized parent (AppShell etc.)
before a privileged request — defeating a hacked app replaying a stolen token.
- prisma: IiosClientRegistry (registered clients allowed to attest, per app) +
IiosAttestationNonce (single-use replay ledger). Migration applied.
- ContextAttestationVerifier + ports (ClientRegistryPort, NonceStorePort) + a dev
signer. Verifies: registered+active client, signature, aud=iios, app_id matches
the token AND is allowed for the client, freshness, single-use nonce. Fail-closed.
- Prisma-backed stores; nonce reserve is atomic via the unique PK (P2002 = replay).
- Tests (9 pass): happy path + the five rejection cases the CEO named
(unknown client, wrong audience, expired, replayed nonce, app-mismatch) +
forged-signature + disabled-client; a DB atomicity test (skips if engine offline).
Decoupled from the request path on purpose — wiring it into the messaging guard
(the three-proof gate) + demoting be-crm to an attestation forwarder is the next step.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>