Console Identity Link
Overview
Console (Walrus Console) and Walrus Memory (WM) are separate Enoki zkLogin applications. The same signed-in human has two different Sui addresses, X in Console, Y in WM, because zkLogin address derivation includes the OAuth client ID (aud) as a direct input (see the Sui zkLogin address derivation spec, different aud values deterministically produce different addresses, even for the identical iss/sub/salt). Console cannot compute Y from its own session; it has to obtain and verify it separately. This document describes that flow and the one API contract WM exposes as part of it.
Who does what
Proving control of Y is entirely Console's responsibility. WM does not participate in that proof, WM has no endpoint that verifies a signature or issues a challenge on Console's behalf. Console has two ways to do this itself:
- Enoki Connect, Console registers WM's Enoki Connect wallet (
registerEnokiConnectWallets, using WM's Public App Slug, seedocs/reference/enoki-connect-requirements.md) and drives a signed-challenge flow directly against that wallet. - Self-custody wallet fallback, the user connects a wallet they hold directly and signs a Console-issued challenge proving they control
Y.
WM's only role is a read-only confirmation, after the fact: once Console believes it has a verified Y, it calls WM's existence-check endpoint to confirm a MemWalAccount actually exists at that address before persisting the console_user ↔ Y link record. WM never sees Console's challenge, signature, or proof, it only ever receives an address and answers a yes/no question about onchain registry membership.
Sequence
Source: reference/console-identity-link.mdUser Console WM
| | |
|--- sign in --------->| |
| |--- Enoki Connect or wallet ---| (Console-only; WM not involved)
|<-- prove control of Y (address derived/signed) ------|
| | |
| |--- GET /api/accounts/Y/exists->|
| |<-- { "exists": true|false } ---|
| | |
| |-- persist console_user <-> Y --| (only if exists: true)
This identity-link step is a prerequisite for a separate, not-yet-built flow that issues Console an owner-scoped token for actually reading memory data. For the broader context this fits into, see the Memory Indexing for Console PRD (internal, requires Notion access). Ticket references: this doc's endpoint is WALM-298; the follow-up token-issuance flow is WALM-297.
API Contract: GET /api/accounts/:owner/exists
The only WM-side endpoint in this flow.
Request
Source: reference/console-identity-link.mdGET /api/accounts/{owner}/exists
owner, a Sui address,0x+ 64 hex characters (case-insensitive; normalized to lowercase server-side before lookup).- No authentication required (see "Why this is public" below).
- Rate-limited per IP (20 req/min, 120 req/hour) plus a deployment-wide aggregate cap, to prevent cheap large-scale address enumeration.
Response, 200 OK
{ "exists": true }
exists is true if owner has ever created a MemWalAccount (that is, it appears in WM's indexed AccountRegistry projection), false otherwise. This is existence in the registry, not current activation status, a deactivated/frozen MemWalAccount still resolves exists: true, by design (see docs/architecture/permanent-registry-design.md: the onchain registry is permanent and append-only, and WM's indexer only processes AccountCreated events, so offchain rows are never removed on deactivation either). If a caller needs to distinguish "never created" from "created but deactivated," this endpoint does not provide that, it only answers whether an account was ever created.
Response, 400 Bad Request
Returned if owner is not a syntactically valid Sui address. Does not touch the database.
Why this is public/unauthenticated: the underlying AccountRegistry is itself a public onchain Sui object, any caller could already determine whether an address owns a MemWalAccount through a direct RPC scan. This endpoint is a convenience/performance wrapper around that already-public fact, not a new information disclosure, so it does not require Console-specific authentication. Abuse is bounded by rate limiting instead of an auth boundary.
CORS: unauthenticated does not mean unrestricted-by-browser. WM's server has its own ALLOWED_ORIGINS-driven CORS layer (deny-by-default), separate from the Enoki Developer Portal's "Allowed Origins" setting described in docs/reference/enoki-connect-requirements.md, the two are unrelated mechanisms that happen to share a name. If Console ever calls this endpoint directly from browser JavaScript rather than server-to-server, Console's origin needs to be added to WM's ALLOWED_ORIGINS env var too, or the browser will block the response. If the identity-link flow stays server-side (as the "persist link record" step implies), this doesn't apply, flagging it so it isn't confused with the Enoki Portal setting if it ever does.
Eventual consistency (indexer lag): exists reflects WM's indexed view of the registry, not a live chain read (see find_account_by_owner in services/server/src/storage/db.rs). A MemWalAccount created moments ago can transiently return exists: false until WM's indexer (services/indexer, accounts_v1 pipeline) processes the corresponding AccountCreated event. Under normal operation this lag is small, but callers building a "link fails right after account creation" UX path should treat a false result as "not confirmed yet," not necessarily "never existed", retrying after a short delay is reasonable. (This is a property of the indexer's operational state in a given environment, not something this endpoint's own logic controls, see docs/reference/enoki-connect-requirements.md's troubleshooting section if a false result persists far longer than expected.)
Implementation: services/server/src/routes/accounts.rs (MystenLabs/MemWal PR #533).
What this flow deliberately does not do
- It does not mint any token or credential. Owner-scoped token issuance for reading memory data is a separate, not-yet-built piece that consumes the verified
Ythis flow produces, it is out of scope here (see the ticket note under "Sequence" above). - It does not let Console sign transactions as
Y. Neither Enoki Connect nor the wallet-signature fallback, as used here, grants Console any signing capability beyond the one-time link proof. - It does not require WM to trust Console's proof. WM's existence check is independent of however Console verified control of
Y, WM simply confirms the address exists, regardless of which method Console used to arrive at it.