feat(auth): unify tokens into v2 user-owned store (v1 SAS becomes read-only)#74
Merged
Conversation
…d-only)
Collapses the two parallel auth systems into one. Tokens now have an
owning username; the v1 SAS store is read-only (existing tokens keep
validating, no new ones can be minted).
Why: the Tokens page minted anonymous v1 SAS tokens while the Users
page (added v0.35.0) managed v2 identity-bound tokens — two doors
with mismatched audit characteristics. With orch yanked, v2 user
accounts had no live consumer except browser login itself. Time to
make them the canonical auth source.
API (server.ts):
- /api/tokens POST routes through v2 FileTokenStore.mint(), accepts
optional `username` (defaults to v2-authed caller; admin can mint
for any user; non-admin payload server-rewritten to self)
- /api/tokens GET returns {me, tokens, users?} — admins get the user
list for picker population; non-admin sees only own tokens
- /api/tokens DELETE/PATCH enforce ownership (non-admin: 403 on
other users' tokens)
- isAuthorized + isWsAuthorized now accept v1 SAS OR v2 session
(was v1-only); becomes async to do the v2 check
Web UI (pickerPage):
- Owner column in the table
- Owner picker on the create form (admins see all users; non-admin
locked to self via `disabled`)
- Auth gate: tokens page requires v2 login
CLI (handlers.ts + index.ts):
- `llmux token create --username <name>` is REQUIRED; no default
- `llmux token list` includes USER column; new `--user <name>` filter
- `llmux token revoke --all [--user <name>]` filters by owner
- `llmux token rename` uses v2 store
- New `--qr-owner <name>` flag on `server start`
Boot QR (handlers.ts:printServerStartQr):
- Mints v2 token for first admin user (or --qr-owner override)
- If no admin exists yet, skips QR + defers to /setup wizard URL
v2 token store (v2/auth/tokens.ts):
- Added `rename(tokenId, name)` to TokenStore interface +
FileTokenStore impl (was previously only on v1 store)
- Exported getV2Stores() from v2-routes.ts so /api/tokens can mint
through the same singleton stores used by /login
v1 sunset:
- authStore.createAuthToken / renameAuthToken / revokeAuthToken /
revokeAllAuthTokens have zero call sites in the codebase now
- authStore.validateAuthToken + listAuthTokens + authEnabled stay
for read-only legacy validation
- Next release will likely delete the v1 store entirely
Build: dist/index.js 375 KB → 382 KB (+7 KB).
Stacks on feat/yank-orch (#72). Smoke test: daemon boots, mints v2
pairing token for first admin user, /api/tokens returns 401 without
auth, returns {me, tokens, users} with v2 session.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
steve-krisjanovs
added a commit
that referenced
this pull request
Jun 26, 2026
…2 user-owned Bundles two significant changes from #72 + #74: - Orch bus + Channels nav surface removed (~2,000 lines deleted) - Tokens unified into v2 user-owned store; v1 SAS becomes read-only See CHANGELOG.md [0.37.0] entry for the full surface inventory and operator impact. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Collapses llmux's two parallel auth systems into one. Tokens minted via the web UI's Tokens page or
llmux token createnow all flow through the v2FileTokenStoreand carry an owningusername. The v1 SAS store becomes read-only: existing tokens keep validating, no new ones can be minted from any code path.Build delta:
dist/index.js375 KB → 382 KB (+7 KB).Surface changes
/api/tokens— all handlers routed through v2FileTokenStorevia newgetV2Stores()export fromv2-routes.ts. POST acceptsusername(default = v2-authed caller; admin can override; non-admin payload server-rewritten to self). GET returns{ me, tokens, users? }(was a bare array). Ownership enforced on PATCH/DELETE.llmux token create --username <name>is required. New--user <name>filter on list/revoke. New--qr-owner <name>flag onserver start.⏭ Skipping pairing QRif no admin yet (defers to/setupwizard URL).isAuthorizedandisWsAuthorizedaccept v1 SAS OR v2 session (both became async).v1 sunset
authStore.createAuthToken / renameAuthToken / revokeAuthToken / revokeAllAuthTokens— zero call sites post-PRauthStore.validateAuthToken / listAuthTokens / authEnabled— kept for read-only legacy validationBackwards compatibility
sas_…tokens keep working — no rotation forced on phones / CI / scripts.llmux token createwithout--usernamenow errors./api/tokensGET response shape changed from bare array to{ me, tokens, users? }.Smoke test (verified on cachy)
[v2] auth ready (2 users); /login, /account, /admin/users available✓ created pairing token (..., owner: stevekrisjanovs)/api/tokens→ 401 without auth,{ok:false, error:"authentication required"}with empty cookie🤖 Generated with Claude Code