Skip to content

fix(proxy): handle SSO session expiry — auto-reauth and clean Anthropic error fallback#4

Open
AntonYeromin wants to merge 8 commits into
mainfrom
worktree-fix+EPMCDME-12317-sso-session-expiry
Open

fix(proxy): handle SSO session expiry — auto-reauth and clean Anthropic error fallback#4
AntonYeromin wants to merge 8 commits into
mainfrom
worktree-fix+EPMCDME-12317-sso-session-expiry

Conversation

@AntonYeromin

Copy link
Copy Markdown
Owner

Summary

  • Adds SessionExpiryHandlerPlugin that detects upstream 401/403 responses and sets context.metadata.sessionExpired = true via the onResponseHeaders hook, preventing the raw 401 body from reaching Bun/JSC and causing the undefined is not an object (evaluating '_.input_tokens') crash
  • Modifies sso.proxy.ts to drain the 401 body after session expiry is detected, attempt SSO re-authentication (attemptSSOReauth), retry the original request with fresh cookies on success, or fall back to a clean Anthropic authentication_error JSON response
  • JWT auth method bypasses re-auth entirely and goes straight to the clean error response
  • Registers the plugin at priority 20 in the plugin registry (before SSOSessionSyncPlugin at priority 100)

Closes EPMCDME-12317

Changes

File Change
src/providers/plugins/sso/proxy/plugins/session-expiry-handler.plugin.ts New — detection plugin
src/providers/plugins/sso/proxy/plugins/__tests__/session-expiry-handler.plugin.test.ts New — 13 unit tests (S1–S5, S8)
src/providers/plugins/sso/proxy/plugins/index.ts Register SessionExpiryHandlerPlugin
src/providers/plugins/sso/proxy/sso.proxy.ts Add upstreamStatusCode propagation, session-expiry short-circuit, attemptSSOReauth, sendSessionExpiredResponse
src/providers/plugins/sso/proxy/__tests__/sso.proxy.session-expiry.test.ts New — 9 unit tests (S6, S7)

Test plan

  • npm run test:unit — 104 files, 1708 passed, 1 skipped
  • SessionExpiryHandlerPlugin sets sessionExpired=true on 401 and 403, no-op on 200/500/absent status
  • sendSessionExpiredResponse returns HTTP 401 with valid Anthropic authentication_error JSON body
  • attemptSSOReauth returns false immediately when authMethod === 'jwt' without calling SSO

AntonYeromin and others added 8 commits May 20, 2026 10:27
When the user's SSO session expires mid-session the upstream CodeMie API
returns a 401 whose body is not Anthropic-format. The Bun-compiled
codemie-opencode binary (JavaScriptCore runtime) crashes trying to read
the usage object: 'undefined is not an object (evaluating _.input_tokens)'.

Fix in three parts:
1. Store upstream HTTP status code in context.metadata before the
   onResponseHeaders plugin hooks run so SessionExpiryHandlerPlugin
   can detect 401/403 without a hook-signature change.
2. After onResponseHeaders, if context.metadata.sessionExpired is set:
   drain the 401 body, call attemptSSOReauth() which runs
   CodeMieSSO.authenticate() (same browser OAuth flow as startup),
   re-inject fresh cookies into the original request headers, and
   forward the retry — streaming the successful response to the binary.
3. If re-auth fails or the auth method is JWT, fall back to
   sendSessionExpiredResponse() which sends a well-formed Anthropic
   authentication_error JSON the binary handles without crashing.

Fixes EPMCDME-12317.

Generated with AI

Co-Authored-By: codemie-ai <codemie.ai@gmail.com>
…attemptSSOReauth

Generated with AI

Co-Authored-By: codemie-ai <codemie.ai@gmail.com>
Real CodeMieProxy + real mock upstream HTTP server, zero vi.mock().
Covers: upstream 401 → authentication_error JSON, upstream 403 → same,
upstream 200 → passthrough regression guard. Adds test:e2e npm script.

Generated with AI

Co-Authored-By: codemie-ai <codemie.ai@gmail.com>
Adds npm run test:e2e after integration tests in both the local ci
script and the test-ubuntu GitHub Actions job. Skipped on Windows
to avoid flaky HTTP server behaviour on that runner.

Generated with AI

Co-Authored-By: codemie-ai <codemie.ai@gmail.com>
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