Skip to content

feat(auth): replace baked API key with scoped key model#2

Open
matthewubundi wants to merge 3 commits intomainfrom
security
Open

feat(auth): replace baked API key with scoped key model#2
matthewubundi wants to merge 3 commits intomainfrom
security

Conversation

@matthewubundi
Copy link
Contributor

Summary

  • Remove baked API key infrastructure: Eliminates the build-time key injection pipeline (api-key.ts, inject-api-key.mjs, BUILD_API_KEY in CI/publish workflows) in favor of user-provisioned scoped keys resolved at runtime via config.apiKey or CORTEX_API_KEY env var
  • Adopt scoped key identity: whoami() endpoint is called during bootstrap to resolve the server-owned user_id from scoped keys, replacing the locally generated install UUID — fixes 403s when the backend enforces key-bound identity
  • Fix CLI and first-turn auth races: Identity resolution is no longer gated behind !isCliInvocation and now completes before any hook or handler fires, preventing auth failures on CLI commands and the first agent turn

Test plan

  • npx tsc --noEmit passes
  • npm test passes — new tests cover whoami, scoped-key 403 variants, identity adoption, CLI identity resolution
  • Manual: verify openclaw cortex status works with a scoped key
  • Manual: verify first-turn recall succeeds without auth race

🤖 Generated with Claude Code

Remove the build-time key injection pipeline (api-key.ts, inject-api-key.mjs,
BUILD_API_KEY in CI/publish workflows) in favor of user-provisioned scoped keys.

- Simplify key resolution to config.apiKey → CORTEX_API_KEY env var
- Add first-run guidance pointing to https://cortex.ubundi.com for key generation
- Add whoami() client method and call it during bootstrap to log authenticated
  user identity and permissions
- Surface scoped-key 403 errors (wrong user_id, missing permission) as clear,
  actionable messages instead of generic "failed: 403"
- Update tests: whoami, scoped-key 403 variants, no-key early return
- Remove stale baked-key references from README and CLAUDE.md
bootstrapClient logged the whoami user_id but never adopted it, so a
scoped key's enforced user_id was ignored — causing 403s on every
subsequent knowledge/recall/capture call with the install-generated ID.

- Return scopedUserId from bootstrapClient so register() can adopt it
- Use the adopted ID for knowledge() and stats() during bootstrap
- Stop swallowing whoami 403s — surface scoped-key and permission errors
  as warnings and abort bootstrap early instead of proceeding to a
  misleading "Cortex connected" message
- Let non-auth whoami failures (network, old backend) fall through at
  debug level so startup isn't blocked
…fires

The whoami identity check was gated behind !isCliInvocation, so CLI
commands (status, search, pair, reset) never adopted the scoped user_id
and sent the local install UUID instead — causing 403s with scoped keys.

Additionally, bootstrapClient ran as fire-and-forget after userIdReady,
meaning recall/capture/tool hooks could fire before whoami finished,
producing avoidable auth failures on the first agent turn.

Split bootstrapClient into resolveScopedIdentity (whoami) and
bootstrapKnowledge (health + knowledge + warmup). Identity resolution
now runs for all paths via identityReady, which all consumers await
before making API calls.
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.

1 participant