Skip to content

ai: forward X-LC-UID so User API Keys can run org AI sessions#294

Merged
maximelb merged 1 commit into
cli-v2from
ai-session-forward-uid
May 17, 2026
Merged

ai: forward X-LC-UID so User API Keys can run org AI sessions#294
maximelb merged 1 commit into
cli-v2from
ai-session-forward-uid

Conversation

@maximelb
Copy link
Copy Markdown
Contributor

Problem

Running limacharlie ai start-session (or any ai session command) under a User API Key failed with 401 "Invalid API key for organization". The user reported it as "the backend requires an Org API key to run an Org based session."

The cause is purely client-side. AI.start_session() and AI._org_request() sent X-LC-OID + Authorization: Bearer <key> but never X-LC-UID. A User API Key is scoped to a user, not an org, so jwt.limacharlie.io can only resolve it when the UID accompanies the secret. Without the UID, the JWT service tries to validate the key as an org key, doesn't find it (user keys live under the user's key store), and rejects the request.

The backend already supports this: ai-sessions' OrgDualAuthMiddleware reads X-LC-UID for the raw-API-key path (middleware_org_jwt.go) and ignores it for JWT auth, so no server change is required — the SDK just has to send the header.

Fix

  • Add AI._org_auth_headers(): always sets X-LC-OID, and adds X-LC-UID when the client has a uid. Safe to send unconditionally (ignored for JWT auth).
  • Route both start_session() and _org_request() through it, so the whole org-scoped AI surface works under a User API Key: start-session, session list/get/terminate/history, usage.

Tests

  • Fixed the mock_org fixture to set _uid = None — otherwise the MagicMock auto-vivifies a truthy _uid and would leak an X-LC-UID header into every request.
  • Added TestOrgRequestUidHeader covering org-scoped (no header) and user-scoped (header forwarded) cases for both start_session and the _org_request path.

Results: AI SDK suites 84 passed (incl. 4 new tests). Full unit suite change is isolated — the only failures (test_search_checkpoint_cli.py, test_search_output.py) are pre-existing and unrelated, confirmed identical on the baseline with these changes stashed.

🤖 Generated with Claude Code

User API Keys are scoped to a user, not an org, so jwt.limacharlie.io
can only resolve them when the UID accompanies the secret. The AI
SDK sent X-LC-OID + Authorization but never X-LC-UID, so a User API
Key could not authenticate ai start-session (or any ai session
command) and the server rejected it as an invalid org key.

ai-sessions' OrgDualAuthMiddleware already reads X-LC-UID for the
raw-API-key path (and ignores it for JWT auth), so no server change
is needed -- the SDK just has to send it.

Add AI._org_auth_headers() which always sets X-LC-OID and adds
X-LC-UID when the client has a uid, and route both start_session()
and _org_request() through it so the entire org-scoped AI surface
(start-session, session list/get/terminate/history, usage) works
under a User API Key.

Tests: fix the mock_org fixture to set _uid = None (otherwise the
MagicMock auto-vivifies a truthy _uid and leaks X-LC-UID into every
request) and add TestOrgRequestUidHeader covering both the
org-scoped (no header) and user-scoped (header forwarded) cases for
start_session and the _org_request path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@maximelb maximelb requested a review from dzimine-lc May 17, 2026 19:05
@maximelb maximelb marked this pull request as ready for review May 17, 2026 19:05
@maximelb maximelb merged commit 0bbfc76 into cli-v2 May 17, 2026
6 of 7 checks passed
@maximelb maximelb deleted the ai-session-forward-uid branch May 17, 2026 19:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant