Skip to content

Stage 7: implement broker-side user auth (Option A — port dexs-backend pattern + add CLIENT_ID_AGENTKEYS to Heima TEE) #63

@hanwencheng

Description

@hanwencheng

Context

PR #61 ships the broker's transport surface (mint-aws-creds, mint-oidc-jwt, OIDC discovery, audit log). The authentication half is still a stub — agentkeys-mock-server accepts any auth_token string and binds it to whatever wallet the caller claims. Anyone with broker.litentry.org can mint a session for any wallet.

This issue tracks the work to ship real auth using the dexs-backend pattern as the reference architecture.

Approach (Option A — port dexs-backend)

Per docs/research/option-a-port-dexs-backend.md, AgentKeys broker absorbs the essential code from dexs-k/dexs-backend — wallet-sig (walletloginlogic.go), email (emailloginlogic.go), Google OAuth (googleoauthcallbacklogic.go), and the pumpx_api callback surface that the Heima TEE worker calls into during omni_userLogin / omni_addWallet.

Heima TEE worker side: add CLIENT_ID_AGENTKEYS so AgentKeys gets its own OmniAccount namespace separate from wildmeta's. Per docs/research/option-a-port-dexs-backend.md §"Phase 0", this is ~250 LOC patch — clones the existing if params.client_id == CLIENT_ID_WILDMETA dispatch block.

Alternative architecture explored (deferred to a separate branch): see Option C issue #64.

Phases

Phase 0 — Heima TEE worker upstream patch

Coordinate with Litentry to land the multi-tenant patch:

  • New constant CLIENT_ID_AGENTKEYS = "agentkeys" in oe_core::auth::constants
  • In tee-worker/omni-executor/rpc-server/src/methods/omni/user_login.rs:73-104: change if params.client_id == CLIENT_ID_WILDMETA to also accept CLIENT_ID_AGENTKEYS with a parallel agentkeys_api HTTP-client config alongside pumpx_api
  • Same multi-tenant logic in submit_user_op_with_auth.rs for the WildmetaBackend ECDSA-pubkey verification path
  • Coordinate timing with Litentry's release cycle

Phase 1 — pumpx_api callback surface in agentkeys-broker

The TEE worker calls back into our broker for first-time-user bookkeeping:

  • POST /v3/account/post_heima_login — user-record creation/update on first TEE login
  • POST /add_wallet — wallet metadata recording (TEE has the seed; we hold the address)
  • GET /get_account_user_id — email→OmniAccount lookup for the email-auth path
  • POST /v1/account/check_hyper_agent_address — main↔agent wallet binding check (port the AgentKeys grant model into this endpoint's response)

Phase 2 — Front-of-house auth (port dexs-backend logic to Rust)

  • Wallet signature — port walletloginlogic.go: EIP-191 message construction, 45-min timestamp window, k256 ecrecover, JWT issuance
  • Email + verification code — port emailloginlogic.go + emailregisterlogic.go: code dispatch via existing AgentKeys SES setup, code storage with TTL
  • Google OAuth — port googleoauthcallbacklogic.go: code-exchange + userinfo fetch + JWT
  • CLI integrationagentkeys init calls /wallet_login (or /email_login, /google_oauth_login) on the broker; stores the bearer in OS keychain

Phase 3 — Broker JWT validation

  • Replace mock-server's opaque-string sessions with TEE-RSA JWT verification (broker fetches TEE's RSA public key once, caches, verifies signatures locally)
  • Drop BROKER_BACKEND_URL indirection (or repurpose as BROKER_TEE_ISSUER)
  • Retire agentkeys-mock-server from the production path; keep in-tree as a --skip-startup-check dev fixture

Phase 4 — Cleanup

  • Remove location = /session/create from setup-broker-host.sh's nginx config (no longer needed once CLI talks to TEE worker for login)
  • Drop the "stub-backend caveat" callouts from operator-runbook §1.1 and stage7-wip docs
  • Update dev-setup §4.2 to show the new agentkeys init invocation

Calendar estimate

8–13 weeks for one engineer, mostly Phase 1 + 2 (ports). Phase 0 calendar is gated on Litentry's review cycle — could be days, could be weeks.

Risks

  • Litentry's review cycle for the multi-tenant patch is the main schedule risk. Mitigation: write the patch ourselves cleanly, run our own forked TEE worker if upstream lags.
  • Inheriting dexs-backend's design baggage (HS256 JWTs, user_id INT identity model, password+TOTP path) — see Option A vs B comparison in docs/research/option-a-vs-b-port-vs-greenfield.md. If this becomes painful, escalate to Option C (separate branch).

Related

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions