From 42bccf5ed21d2af095f084874b59272f3023ab6d Mon Sep 17 00:00:00 2001 From: Joshua Date: Wed, 18 Feb 2026 20:15:39 -0800 Subject: [PATCH] Forward wallet session tokens in launcher API calls --- README.md | 1 + app/app.js | 29 +++++++++++++++++++++++++++-- docs/integration-contract.md | 13 +++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 956b9d8..361cf4f 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ Wallet automation helpers remain available in advanced controls: 3. `Sign payer proof` signs distinct-payer ownership proof and fills `payerProof`. 4. `Send membership tx` submits the quote transaction via `eth_sendTransaction` and fills `confirmTxHash`. 5. Membership confirm can optionally attach on-ramp attestation fields (`identity_assurance_level`, `identity_attested_by`, `identity_attestation_id`) for provider-integrated flows. +6. Wallet verify returns a session token; launcher forwards it on marketplace/member/governance API calls via bearer + `X-Edut-Session`. Policy behavior in launcher shell: diff --git a/app/app.js b/app/app.js index 0789d6c..b01b40f 100644 --- a/app/app.js +++ b/app/app.js @@ -9,6 +9,8 @@ const state = { lastCheckoutQuote: null, lastStatus: null, channelReady: false, + walletSessionToken: "", + walletSessionExpiresAt: "", }; function nowISO() { @@ -133,9 +135,14 @@ function sleep(ms) { } async function request(method, path, body) { + const headers = { "Content-Type": "application/json" }; + if (state.walletSessionToken) { + headers["X-Edut-Session"] = state.walletSessionToken; + headers.Authorization = `Bearer ${state.walletSessionToken}`; + } const opts = { method, - headers: { "Content-Type": "application/json" }, + headers, }; if (body !== undefined) { opts.body = JSON.stringify(body); @@ -260,12 +267,22 @@ function buildIntentTypedData(intent, origin) { } async function onConnectWallet() { + const previousWallet = normalizedAddress($("walletAddress").value); const provider = await requireProvider(); const accounts = await provider.request({ method: "eth_requestAccounts" }); if (!accounts || accounts.length === 0) { throw new Error("wallet provider returned no accounts"); } - $("walletAddress").value = normalizedAddress(accounts[0]); + const nextWallet = normalizedAddress(accounts[0]); + $("walletAddress").value = nextWallet; + if (previousWallet && previousWallet !== nextWallet) { + state.walletSessionToken = ""; + state.walletSessionExpiresAt = ""; + logLine("wallet session reset", { + previous_wallet: previousWallet, + next_wallet: nextWallet, + }); + } const chainHex = await provider.request({ method: "eth_chainId" }); const providerChainID = Number.parseInt(chainHex, 16); if (Number.isFinite(providerChainID) && providerChainID !== chainID()) { @@ -400,7 +417,15 @@ async function onVerify() { if (out.designation_code) { $("designationCode").value = out.designation_code; } + state.walletSessionToken = String(out.session_token || "").trim(); + state.walletSessionExpiresAt = String(out.session_expires_at || "").trim(); logLine("wallet verify", out); + if (state.walletSessionToken) { + logLine("wallet session active", { + wallet: requireWallet(), + session_expires_at: state.walletSessionExpiresAt || "unknown", + }); + } refreshOverview(); } diff --git a/docs/integration-contract.md b/docs/integration-contract.md index e714d6c..01fa9ef 100644 --- a/docs/integration-contract.md +++ b/docs/integration-contract.md @@ -18,6 +18,19 @@ Launcher integrates with EDUT web/backend contracts as follows: 12. `GET /governance/install/status` 13. `GET /member/channel/events` +## Wallet Session Contract + +1. `POST /secret/wallet/verify` returns `session_token` and `session_expires_at`. +2. Launcher must attach session token on wallet-scoped calls using: + - `Authorization: Bearer ` (preferred) + - `X-Edut-Session: ` (compatibility) +3. Wallet change must clear cached session token before further calls. +4. Endpoints that require membership/admin authority can fail with: + - `wallet_session_required` + - `wallet_session_invalid` + - `wallet_session_expired` + - `wallet_session_mismatch` + ## Deterministic Requirements 1. No runtime activation without entitlement proof.