# Client-assertion-backend compatibility probe — 2026-10-04 UTC Question: can Reams replace its confidential token relay with the 2025 [client-assertion-backend proposal](https://github.com/bluesky-social/proposals/tree/b46b8414da725eb0867ac605a76f6603e4ed623e/0010-client-assertion-backend), keeping browser-owned credentials and a smaller independently deployed signer? ## Result **Neither tested provider enforces the assertion's `cnf.jkt` binding at PAR, authorization-code exchange or refresh.** Do not adopt the proposal based only on these providers accepting requests that contain `cnf`. | Probe | PDS 0.5.1 / provider 0.18.1 | PDS 0.5.19 / provider 0.20.2 | | --- | --- | --- | | PAR, matching assertion/proof key | 201 accepted | 201 accepted | | PAR, mismatched assertion/proof key | **201 accepted** | **201 accepted** | | Code exchange, matching binding | 200, tokens issued | 200, tokens issued | | Code exchange, mismatched binding | **200, tokens issued** | **200, tokens issued** | | Refresh, matching binding | 200, token rotated | 200, token rotated | | Refresh, mismatched binding | **200, tokens issued** | **200, tokens issued** | | Invalid application signature at PAR | 400 `invalid_client` | 400 `invalid_client` | | Valid proof from wrong authorized device at code exchange | 400 `invalid_grant` | 400 `invalid_grant` | | Valid proof from wrong authorized device at refresh | 400 `invalid_grant` | 400 `invalid_grant` | Ordinary DPoP grant binding is enforced, but that does not bind a client assertion issued to device A against reuse by device B. That additional check is the proposal's key requirement. ## Method and provenance - Probe: `scripts/spikes/client-assertion-binding.test.mjs`. - Real disposable PDS/PLC/HappyView processes; HTTPS client metadata with a fresh P-256 public signing key; actual PDS login and consent; genuine PKCE, nonce, DPoP signatures and signed client assertions. No provider responses are mocked. - Every code/refresh case starts a separate login; negative confirmation cases alter only `cnf.jkt`, retaining the genuinely authorized device and its proof. Wrong-session controls instead supply an independently valid proof/key pair. - The test driver holds signer/browser credentials for the probe. This is not a shipped assertion service or a browser-packaging test. - Fixture runner: `/nix/store/09xc42j9lkqrdc5fwaq6if3mkb37dq2g-pds-0.4.5001/bin/pds`, containing PDS package 0.5.1 / provider 0.18.1. - Second runner: the companion checkout's installed PDS package 0.5.19 / provider 0.20.2. A temporary launcher uses its real `PDS.create`/`start` API. - Companion harness source: `bbe5834261d266a6847009d409d3a69d4abf6aa8`. - HappyView source: `6035c557e3ff2939eb0923bb1161663106c97223`, with the existing local spaces patches. HappyView starts as part of the fixture; OAuth requests and consent go directly to the PDS, not a HappyView-fabricated authority. - Local CA/private-network exceptions are confined to the disposable fixture. The broad scope is the existing harness's disposable-account scope, not a proposed production permission request. The initial newer-provider run exposed an environment/driver mismatch, not an OAuth capability result: its SQLite native dependency needed rebuilding and its consent API uses `did` instead of older `sub`. Both were repaired; the final complete run passed both profiles, with 18 recorded observations and zero skips. **A passing probe means controls and observations succeeded; its binding verdict is `not-enforced` for both profiles.** A future denial-only run is marked `inconclusive-denial`, not automatically certified as CAB support. Ordinary-auth controls require no successful result and the expected `invalid_client` or `invalid_grant` classification. Final run ID: `149d6c12-af20-4779-a5e0-9d3630906d15`, started at `2026-10-04T03:33:08.067Z`. Probe SHA-256: `cf77793b88e61dc1c1bd75eb268acff5b22feda2dbaee7df9d9829dc5846dd24`. Each result captures the shared run ID, proposal pin, probe/harness/lock hashes, checkout revisions/dirty flags, installed dependency lock integrities, versioned consent API profile, Node version and HappyView tracked-patch hash. The completed pair is published atomically as `latest.json` after successful fixture teardown; interrupted runs cannot mix profiles. Lockfile integrities identify declared dependencies, not an independent integrity audit of installed package contents. ## Reproduction The newer installed PDS requires its native SQLite dependency: ```sh nix develop /home/anish/usr/automerge-atproto --command sh -c \ 'export PATH="$PATH:/run/current-system/sw/bin"; npm rebuild better-sqlite3 --build-from-source' ``` Run that prerequisite from the companion checkout. Then, from Reams: ```sh nix develop /home/anish/usr/automerge-atproto --command sh -c ' export PATH="$PATH:/run/current-system/sw/bin" AUTOMERGE_ATPROTO_ROOT=/home/anish/usr/automerge-atproto \ HAPPYVIEW_SOURCE=/home/anish/usr/automerge-atproto/tmp/happyview \ RUN_CLIENT_ASSERTION_PROBE=1 \ node --test scripts/spikes/client-assertion-binding.test.mjs ' ``` Redacted output is retained in: - `.invariant-artifacts/client-assertion-binding/latest.json` - `.invariant-artifacts/client-assertion-binding/149d6c12-af20-4779-a5e0-9d3630906d15/nix-fixture.json` - `.invariant-artifacts/client-assertion-binding/149d6c12-af20-4779-a5e0-9d3630906d15/installed-pds.json` The evidence contains statuses, error codes and package versions, not private keys, passwords, tokens, codes, cookies or PAR request URIs. ## Decision boundary This is two real local reference-provider versions, not a verdict on every production PDS or the live `bsky.social` entryway. Live behavior requires our public client metadata, a configured confidential client and an authorized disposable account; none was provisioned or used in this run. For compatibility with the tested providers, keep the existing relay behind a separately deployed Reams auth service. SQLite or a separate PostgreSQL database can persist its metadata; this is independent of HappyView's Postgres choice. The smaller CAB signer remains a candidate when provider enforcement is proven. Fresh adversary review approved the narrow negative finding. Its harness classification/control/provenance recommendations were applied before the final run; publication was additionally moved after teardown. This is a binding counterexample, not a captured-assertion replay experiment or complete conformance gate. No database backend or separate auth-service deployment was tested here.