Account secrets reach the browser in the accounts wire shape
Table of Contents
This page is a capture in the inbox bucket of the product backlog — a pre-sprint idea, not yet pulled into a sprint as a story.
1. What
The generated account wire shape carries three credential fields to every caller
of iam.v1.accounts.list and iam.v1.accounts.get: password_hash,
password_salt and totp_secret. The BFF serves those two subjects at
/api/accounts and /api/accounts/:key, so the values reach the browser.
2. Why
Found on 2026-09-23 while documenting the IAM user journeys (User Journeys). It breaks the acceptance criterion "no secret field reaches the browser" that the IAM map set, and it is a live defect rather than a design gap.
Evidence:
projects/ores.iam/modeling/ores.iam.account.orgdeclarespassword_hash,password_saltandtotp_secretwithout:sql_only: true. The same file marksservice_password_hash:sql_only: trueand says why: it never goes on the wire.- Because those three lack the marker, the generator emits them into the domain
type:
projects/ores.web/packages/wire-protocol/src/generated/iam/domain/account.tsdeclarespassword_hash: string,password_salt: stringandtotp_secret: stringoninterface Account. - The responses carry that type whole:
ListAccountsResponse.accounts: Account[]andGetAccountResponse.account: Account | nullinprojects/ores.web/packages/wire-protocol/src/generated/iam/protocol/account_protocol.ts. projects/ores.web/packages/bff/src/server.tsregisters the generated account routes, which return those responses to the browser unchanged.
Scope sweep, 2026-09-23: every entity model under projects/*/modeling/ was
checked for fields whose name matches hash, secret, password, token, salt or
credential. Only ores.iam.account.org holds real credentials, and exactly three
of its fields lack the marker. service_password_hash is correctly excluded, and
password_reset_required is a boolean flag rather than a secret.
The hand-written *_messages.org request and reply models are a separate
concern: a cleartext password on a save or login request, and the token in a
login reply, are intended. Do not "fix" those.
Nothing works around this today. The fields are on the wire now.
The fix has a precedent in the same entity. Mark all three :sql_only: true, as
service_password_hash already is, and read them where authentication needs them
through the repository rather than through the domain type. Decide separately
whether totp_secret belongs in the save_account_request input, where it is
legitimately set.
Not to be confused with the journey gap log: the journeys record what the screens need and do not have. This is a defect in what the server already sends.
3. References
projects/ores.iam/modeling/ores.iam.account.org— the fields without the marker.projects/ores.web/packages/wire-protocol/src/generated/iam/domain/account.ts— the generated domain type.projects/ores.web/packages/wire-protocol/src/generated/iam/protocol/account_protocol.ts— the responses that carry it.projects/ores.web/packages/bff/src/server.ts— the routes that serve it.