Skip to content

opencode: refresh Databricks token via loopback proxy (fixes ~1h mid-session 401s) - #337

Open
kishor-rkrishnan wants to merge 1 commit into
databricks:mainfrom
kishor-rkrishnan:fix/opencode-token-refresh-proxy
Open

opencode: refresh Databricks token via loopback proxy (fixes ~1h mid-session 401s)#337
kishor-rkrishnan wants to merge 1 commit into
databricks:mainfrom
kishor-rkrishnan:fix/opencode-token-refresh-proxy

Conversation

@kishor-rkrishnan

Copy link
Copy Markdown

Problem

Long-running ucode opencode sessions fail roughly every hour with 401 Invalid Token and cannot recover without a restart. This is the OpenCode side of #190.

Root cause

ucode opencode writes the Databricks OAuth token into opencode.json (the provider Authorization header + apiKey). OpenCode resolves that config once at process start and never re-reads it, so when the token reaches its ~1h OAuth lifetime every subsequent request 401s. The existing background thread (_refresh_forever) rewrites opencode.json every 30 min, but the running OpenCode process ignores the file after launch, so the rewrite has no effect.

(ucode claude is unaffected — it uses Claude Code's apiKeyHelper, which re-fetches the token on a 401.)

Fix

Reuse the loopback refresh proxy already used for relayed Claude (gateway_proxy): point each OpenCode provider's baseURL at the proxy, which overwrites the Authorization header with a freshly-minted token on every request via its own background _TokenCache refresher. The token written into opencode.json becomes a bootstrap value the proxy replaces per request, so it never goes stale mid-session.

  • One proxy serves all providers — the anthropic, gemini and mlflow paths all live under the same workspace host, so the proxy only swaps host + Authorization and forwards the path unchanged.
  • start_proxy gains upstream_base and swap_header keyword arguments; their defaults reproduce the existing relayed-Claude behavior exactly (the unchanged header tests still pass), so this is purely additive for the Claude path.
  • The obsolete per-launch file-rewrite refresher (_refresh_forever) is removed.

Scoped to this single behavior (the static-token mid-session death). The separate concurrent-refresh token-rotation race (#190 / #197) is intentionally out of scope here.

Testing

  • uv run pytest — unit suite passes (the only failures are pre-existing environment/e2e ones unrelated to this change).
  • uv run ruff check . and ruff format --check . — clean.
  • New unit tests: swap-header selection + upstream-base override (test_gateway_proxy.py); loopback URL rewrite (test_agent_opencode.py).
  • Verified end-to-end against a real AI Gateway workspace with the real opencode binary: with an expired token in the config, requests sent straight to the gateway return 401 (bug reproduced); the same expired-token config pointed at the proxy returns 200 (fixed). Also confirmed the gateway authenticates on Authorization and tolerates the stale x-api-key OpenCode still sends, so swapping Authorization alone is sufficient.

@@ -1 +1 @@
"""Loopback refresh proxy for relayed Anthropic (Claude Max/Team/Enterprise).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of reusing this proxy which is meant for a different provider, can you please create an opencode specific proxy

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — moved this into a dedicated opencode_proxy module, so gateway_proxy is now untouched (identical to main). The new proxy is purpose-built for OpenCode (swaps the Authorization header, forwards to the workspace host). Thanks for the review!

…fix ~1h mid-session auth failures

OpenCode resolves opencode.json once at process start and never re-reads it, so
the Databricks OAuth token baked into the config (the Authorization header) goes
stale at the ~1h OAuth token lifetime and every request then fails with 401
Invalid Token, killing long-running sessions. The background thread that
rewrites the config every 30 min does not help, because the running process
ignores the file after launch.

Add a dedicated OpenCode loopback proxy (opencode_proxy) rather than extending
the relayed-Anthropic proxy, which is provider-specific. ucode opencode points
each provider's baseURL at it; the proxy overwrites the Authorization header with
a freshly-minted token on every request via its own background refresher, so the
token never goes stale mid-session. One proxy serves all providers since they
share the workspace host. The obsolete per-launch file-rewrite refresher is
removed.

Tests: unit coverage for the proxy's Authorization swap + workspace-root
forwarding, and the loopback URL rewrite.
@kishor-rkrishnan
kishor-rkrishnan force-pushed the fix/opencode-token-refresh-proxy branch from 8aa819b to 9947ddd Compare August 14, 2026 17:33
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