Skip to content

fix: web UI requests every scope, so Settings opens with an API key - #378

Merged
saucam merged 1 commit into
mainfrom
fix/web-settings-scope
Oct 11, 2026
Merged

saucam merged 1 commit into
mainfrom
fix/web-settings-scope

Conversation

@saucam

@saucam saucam commented Oct 11, 2026

Copy link
Copy Markdown
Collaborator

What this fixes

Opening Settings in the web UI fails with Missing scope: settings:read when you're signed in with an API key.

The web UI asks ZeroID for a token using its own hand-written list of scopes. That list was never updated when the settings and fleet scopes were added. The daemon only allows what the token carries, so Settings and the fleet board were unreachable from the web UI, whatever the key itself allowed.

The web UI now asks for every scope codeoid defines, the same way codeoid login already does (#303). The test that guards the CLI's list now guards the web list too, so it can't fall behind again.

This alone may not clear the error for an existing key. ZeroID only grants scopes the key's identity allows. An identity created with an older scope list still caps the token, whatever codeoid asks for. On the machine where this was found, the identity was missing exactly settings:read, settings:write and fleet:read. That's a ZeroID setup issue, not a codeoid one; see the issue note below.

Verification

  • Exchanged a real key against local ZeroID with the new scope list. ZeroID granted 15 of the 18 scopes, dropping exactly the three that the key's identity doesn't allow. That confirms the request is now correct and that the remaining gap is the identity's own limit.
  • Tests: login-scope-drift.test.ts passes (5 tests), as do the web auth tests (38). Typecheck and lint are clean for both the daemon and the web UI.
For agents
  • The fix. web/src/lib/auth.ts: DEFAULT_WEB_SCOPES = ALL_SCOPES_STRING (imported from @highflame/codeoid-protocol, a file: dependency of the web UI).
  • Tests. src/tests/login-scope-drift.test.ts adds a "web UI scope set" check against the source. src/cli.ts now names that test correctly in its comment.
  • ZeroID scope chain (zeroid/internal/service/oauth.go apiKeyGrant): requested ∩ key.scopes ∩ key policy ∩ identity policy ∩ identity.allowed_scopes.
    • An identity created by hand with the old CLI list (which included tools:* and lacked settings:* / fleet:read) caps every token.
    • The fix is PATCH /identities/{id} with the full allowed_scopes, or a new identity and key.
  • Related ZeroID gap. ZeroID's built-in codeoid audience profile (embedded-UI sign-in, defaultAudienceScopeProfiles and allowedProfileScopes) also lacks settings:*, fleet:read and pipeline:*.

🤖 Generated with Claude Code

The web UI exchanges an API key for a token with its own scope request,
a hand-written list that never gained settings:read / settings:write or
fleet:read. The daemon enforces the minted scopes verbatim, so a web
session signed in with a key could not open Settings ("Missing scope:
settings:read") or the fleet board, whatever the key allowed.

DEFAULT_WEB_SCOPES is now ALL_SCOPES_STRING, like the CLI's login set
(#303). login-scope-drift.test.ts now guards the web list too, and the
CLI comment names that test correctly.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@saucam
saucam merged commit b253d06 into main Oct 11, 2026
4 checks passed
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