Convention question: how should hero_* services consume proxy-injected identity headers? + what is hero_osis's identity domain for? #191
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What's the question
hero_proxyis the edge — terminates TLS, runs auth (bearer / OAuth / secp256k1 signature / IP-auto-login), and injects three identity headers on every forwarded request:X-Hero-User: <username>— the authenticated principalX-Hero-Context: <integer>— context id, sourced fromproxy.users.contextsince commit5f7bb04(proxy #23, "source X-Hero-Context from authenticated user, not route")X-Hero-Claims: <comma-separated>— flattened RBAC claims via group → role → claim BFSFive backends I audited handle these five different ways. There's no stack convention, no portable client across services, and one big load-bearing question about hero_osis's identity domain that needs an answer before any convention can land.
State today (5 backends, 5 different answers)
X-Hero-User?X-Hero-Context?X-Hero-Claims?external_idcol?user.me--auth-mode=devexternal_id, decoupled from proxyImplications:
X-Hero-Userhas full identity in collab, no reachable identity in whiteboard (noexternal_idto map onto), is effectively anonymous in voice/slides, and is the wrong shape for agent (which expects a JWT).X-Hero-Claimsis wire-defined but operationally inert. Collab logs it; agent forwards it to MCP downstreams; nobody makes a permission decision on it. The proxy spends BFS work computing it on every request.X-Hero-Contextis sourced and injected but no service scopes data by it. The denormalizedproxy.users.contextsource decision (5f7bb04) settled the proxy side; the downstream side is unanswered.Concrete reference impl (one possible answer for the collab side)
Recently merged in hero_collab as one option for "how a downstream service consumes proxy-injected identity":
feat(auth): bootstrap collab admin from proxy.is_admin + dev-mode honesty— on firstuser.me, querieshero_proxy_sdk::users_list(3s timeout) and grants collabadminif proxy reportsis_admin=1. Falls back to "first-user-on-empty-DB grants admin" when proxy is unreachable (mirrors hero_osis'sfirst user_create gets Owner role). Plus a 4-line shim that drops upstreamX-Hero-Userwhen--auth-mode=dev(collab declares itself the source of truth for identity in dev mode).This is collab's local choice, not a stack convention. Nothing about #21 obliges voice / slides / whiteboard / agent to do anything similar.
The load-bearing question — what is hero_osis's identity domain for?
hero_osis'sidentityschema definesUser,Group,Session,Device,Profile,Contact,SshKey, plus a full ed25519 challenge-responseAuthService. None of it is in the request path of any web-facing app:userstable; after5f7bb04it explicitly does NOT live-sync identity from osis (thecontext_sync.rsmodule that briefly existed was reverted within hours of being added).X-Hero-Userfrom proxy; never queries osis for identity.hero_osis_sdkand connects at startup, but the connection is not in the auth path.Meanwhile osis's
communicationdomain is being actively developed (e.g.list_messagesaddede0e02ddon Apr 19). So the codebase is alive — identity just isn't in the operational flow.Three plausible explanations the team needs to pick one of:
proxy.users; for key-based clients, it'sosis.User."proxy.usersis transitional.5f7bb04's revert was tactical (that specific sync was wrong), not strategic (osis irrelevant). If so: path and timeline?Without a chosen answer, every new app maintainer faces the same fork ("wire to proxy or osis?") with no canonical answer; the default ends up being "wire to neither" (voice, slides) or "wire to proxy and ignore the rest" (collab).
Questions
hero_osis's identity domain for? (one of the three above, or a fourth I'm missing)X-Hero-Userhandling? Reference impl in collab PR #21 — do other services adopt this pattern, or is per-service freedom intentional?X-Hero-Claims: enforce it or drop it? Currently nobody decides on it; the proxy spends compute producing it on every request.Question 1 precedes the others — the answer changes whether
external_idshould map toproxy.users.idorosis.User.sid, and whetherdisplay_nameshould be sourced from proxy or osis. If there's appetite for a one-page "identity contract for hero apps" that codifies the answers, happy to draft it.I agree it is very important to settle this.
@despiegk @timur have been working on this refactoring I think they should share their POV.
Thanks @sameh-farouk