Skip to content

docs: decide CipherBox issues the Core Kit identity token - #64

Merged
FSM1 merged 2 commits into
mainfrom
docs/adr-0008-identity-token-issuer
Aug 11, 2026
Merged

docs: decide CipherBox issues the Core Kit identity token#64
FSM1 merged 2 commits into
mainfrom
docs/adr-0008-identity-token-issuer

Conversation

@FSM1

@FSM1 FSM1 commented Aug 11, 2026

Copy link
Copy Markdown
Owner

What this decides

A CipherBox login has two authentications, and the blueprint conflates them:

  1. Unlocking the Core Kit — an identity provider vouches for the person; the Core Kit returns the TSS key.
  2. Authenticating to the API — the engine signs a challenge with the derived identity key.

#28 D5 governs (2) and is correct as written. (1) was never decided. v2 built it as Web3Auth's hosted OAuth, in the client wiring; v1 had CipherBox mint a JWT against a custom verifier.

The account model cannot distinguish them, because the Core Kit yields the same key whichever provider vouched — so blueprint/api.md's "Account = the Web3Auth-derived secp256k1 identity key" holds under both, and the issuer was chosen by accident rather than by decision.

Three decisions follow:

  • D1 — CipherBox issues the identity token the Core Kit consumes, via a custom verifier over its own JWKS. Passwordless email returns to the API. Google keeps its own OAuth client ID, distinct from the Web3Auth project one.
  • D2 — Wallet login is a first-class first login, on web only. This is the clause that amends Decide: v-next feature set #5. It is web-only because the Tauri webview reaches no wallet — a platform property, not a deferred feature.
  • D3 — One host-agnostic orchestration package; credential collection injected per host. The boundary is drawn at credential collection, one step earlier than v1 drew it.

Nothing about the account model, challenge-signature login, the engine-held token lifecycle, or the CredentialStore split changes.

Why now

Hand UAT on a local stack found all three login methods down, for three different reasons — one of which (Google answering 401 invalid_client, because the Web3Auth project client ID is passed where the provider's belongs) is a plain defect that holds regardless of this ADR.

Evidence it rests on

  • v1 shared no login code across hosts: ~3,600 lines in apps/web against ~2,400 in apps/desktop, implementing the same flows twice. The shared boundary sat at getAccessToken, so everything producing a token was per-host by construction.
  • That boundary drifted measurably: MAINNET vs DEVNET for the same environment, a device-factor recovery branch on one host only, viem/siwe against a hand-concatenated EIP-4361 string, and an email-OTP failure where the JS half read a compile-time API URL and the Rust half a runtime one.
  • The Core Kit itself ran correctly in the Tauri webview, so it is not the obstacle.
  • Google credential collection genuinely cannot be shared: GIS does not work in that webview, the fallback flow needs a redirect_uri, and a packaged Tauri origin is tauri://localhost, which Google rejects.
  • v1 wrote desktop loginWithWallet and never wired it.

Cost to be honest about

apps/desktop/frontend is a 43-line static HTML file with no bundler, no TypeScript and no dependencies, and the shell links no engine. D3 needs a desktop JS app to exist first. That is new build configuration, not a refactor, and it is the largest single cost here.

Rejected, with reasons in the ADR

Moving the orchestration into the engine — attractive, since the engine is shared by construction and already performs challenge-signature login, SIWE challenge/login/link, refresh and logout. It fails on two counts: the Core Kit is a JS SDK owning DOM and redirect flows, so the engine would need a callback seam against SeamSet's completeness gate; and under D1 the API exchange precedes the login secret, so the engine would need a command surface that works unstarted.

Implemented by FSM1/cipher-box#1253, which will decompose into linked issues per layer.

A CipherBox login has two authentications and the blueprint conflates them:
unlocking the Core Kit, and authenticating the derived key to the API. #28 D5
governs the second and is correct. The first was never decided — v2 built it as
Web3Auth hosted OAuth in the client wiring, where v1 had CipherBox issue a JWT
against a custom verifier.

The account model cannot tell them apart, because the Core Kit yields the same
key whichever provider vouched. So making CipherBox the issuer again costs
nothing in the account model and returns two things: a wallet that can start a
session, and passwordless email the API owns.

Amends #5 so the wallet method is first-class on web. It stays absent on desktop
because that webview reaches no wallet — v1 wrote that path and never wired it.

Draws the sharing boundary at credential collection rather than at the bearer
token, which is where v1 drew it and where it drifted.
@FSM1

FSM1 commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

Marked Accepted — not implemented in 65ef063, and the status now names FSM1/cipher-box#1253 as the implementation umbrella.

That umbrella is decomposed into six sub-issues with dependency edges: FSM1/cipher-box#1256 (the Google client-ID split, independent of this ADR and ready now), FSM1/cipher-box#1257 (the API issues the identity token), FSM1/cipher-box#1258 (API-owned passwordless email), FSM1/cipher-box#1259 (extract the shared login package), FSM1/cipher-box#1260 (wallet as a first login), and FSM1/cipher-box#1261 (a desktop frontend that can log in).

The blueprint statement of this decision is FSM1/cipher-box#1255, held as a draft so it does not land ahead of the decision it records — it can go ready once this merges.

@FSM1
FSM1 merged commit 90ad872 into main Aug 11, 2026
@FSM1
FSM1 deleted the docs/adr-0008-identity-token-issuer branch August 11, 2026 15:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant