Skip to content

Let an admin mint an API key on behalf of a user - #2902

Merged
lukemarsden merged 1 commit into
mainfrom
feature/002391-fix-critical-helixos
Jul 30, 2026
Merged

Let an admin mint an API key on behalf of a user#2902
lukemarsden merged 1 commit into
mainfrom
feature/002391-fix-critical-helixos

Conversation

@binocarlos

Copy link
Copy Markdown
Collaborator

Pairs with helixml/helixos#90.

An orchestrator that runs agents for a team currently holds one shared API key, so
Helix records every agent's work against that one account and resolves its Claude
subscription. One person's expired token breaks the whole fleet, and nobody can
run their own agent on their own subscription.

#2899 and #2900 addressed that by routing credentialsCredentialOwnerID
plus a delegation grant. That works, but the grant is org-shaped: it says "this
org's automation may spend my quota", which is broader than "my own agents may".

Holding a key per person removes the need for any of that. Sessions and triggers
the orchestrator creates are genuinely owned by the person, so their subscription
applies through Helix's ordinary resolution — no delegation, no new concepts.

The endpoint

POST /api/v1/admin/users/{id}/api-keys?name=…, admin-only, returns the key.

  • Idempotent per (user, name). An orchestrator mints on every login or
    reconcile pass; a fresh key each time would leave a pile of live credentials.
  • Refuses to mint for a subject with no Helix user. This is the boundary that
    keeps it safe once the orchestrator is web-facing: signing up there must not
    be enough to get an identity minted here. Both sides share an IdP, so someone
    who has logged into Helix already has a row; someone who hasn't is not a person
    we will act as.

Nothing else changes. This is additive — no existing behaviour is touched.

Why this is safe to add

The privilege already exists: an admin key can already do anything, including
minting keys. What changes is that the orchestrator's sessions stop all being
attributed to one service account, so "who ran this" becomes answerable — an
audit improvement, not just a credentials one.

Worth stating plainly, though: this lets an admin act as any user without their
involvement, which is exactly the property #2899's consent gate was designed to
avoid. That gate remains the right mechanism for member-to-member delegation.
This is for the narrower case of a trusted first-party orchestrator, where the
alternative is the whole fleet sharing one account.

Testing

go build ./pkg/server/ clean, go test -run TestAdmin ./pkg/server/ passes.
Five new cases: the key is owned by the target user and not the caller;
re-minting the same name returns the existing key without creating another;
non-admins get 403; an unknown user gets 404 rather than a minted identity; and
name is required.

go vet reports two pre-existing issues in mcp_backend_external.go, untouched
here.

NOT tested against a running stack — no Helix dev stack in this environment.
The handler logic is unit-tested; the round trip from the orchestrator is not.

Deploy note

The HelixOS service account on meta.helix.ml is not currently an admin
verified: GET /api/v1/users returns 401 with its key. Until that's granted, the
paired PR mints nothing and every bot stays on the shared key, so both sides are
inert rather than broken.

An orchestrator dispatching work for a team had one shared key, so every
agent it launched authenticated as that key's owner. Minting a key per
person lets it act as each of them instead, which is what makes their own
Claude subscription apply through the ordinary path.

POST /admin/users/{id}/api-keys, admin-only, idempotent per (user, name)
so minting on every login does not pile up credentials. Refuses to mint
for a subject with no Helix user: signing up to the orchestrator must not
be enough to get an identity here once it is web-facing.

Spec-Ref: helix-specs@6789a48:002391_fix-these-critical-bugs
@lukemarsden
lukemarsden merged commit cd48108 into main Jul 30, 2026
5 checks passed
@lukemarsden
lukemarsden deleted the feature/002391-fix-critical-helixos branch July 30, 2026 11:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants