Problem
OpenCode stops working in CODA after PAT rotation. All API calls fail with 401 Unauthorized.
Root Cause
Three layers of process isolation conspire to keep stale tokens alive:
-
PTY environment is frozen at spawn time — When a terminal session is created, subprocess.Popen(env=os.environ.copy()) snapshots the parent's environment. The parent process updates os.environ["DATABRICKS_TOKEN"] on rotation, but the child bash process (and anything launched from it) never sees the update.
-
OpenCode caches credentials at startup — OpenCode reads ~/.local/share/opencode/auth.json once when launched and holds the token in memory for the lifetime of the TUI process. Even though cli_auth._update_opencode() writes the new token to disk every rotation, OpenCode never re-reads it.
-
Content-filter proxy forwards stale auth headers — The proxy at localhost:4000 (which all OpenCode traffic passes through) copies the Authorization header from OpenCode and forwards it verbatim to Databricks. Since OpenCode sends the stale token, the proxy sends the stale token.
When PAT rotation runs (pat_rotator._rotate_once()), it:
- Mints a new 4-hour token
- Revokes the old token via
/api/2.0/token/delete
- Updates
os.environ, ~/.databrickscfg, and all CLI auth files on disk
The revocation is what makes this fatal — the old token doesn't just expire naturally, it's immediately invalidated. OpenCode's next API call hits a 401.
Affected Components
| Component |
Token Source |
Updated on Rotation? |
Re-reads at Runtime? |
| Databricks CLI |
~/.databrickscfg |
Yes (file) |
Yes (per invocation) |
| Claude Code |
~/.claude/settings.json |
Yes (file) |
Likely yes |
| OpenCode |
auth.json + env var |
Yes (file), No (env) |
No — cached at startup |
| Content-filter proxy |
Forwarded header |
N/A |
N/A — pass-through |
Fix
PR #105 — Make the content-filter proxy read the current token from ~/.databrickscfg (which the PAT rotator always keeps current) and override the Authorization header before forwarding to Databricks. 30-second file read cache to avoid per-request I/O.
This is the right layer to fix it because:
- The proxy already intercepts all OpenCode → Databricks traffic
- No changes needed to OpenCode itself
- Works for any future CLI tool routed through the proxy
.databrickscfg is the canonical token source, always updated by the rotator
Problem
OpenCode stops working in CODA after PAT rotation. All API calls fail with 401 Unauthorized.
Root Cause
Three layers of process isolation conspire to keep stale tokens alive:
PTY environment is frozen at spawn time — When a terminal session is created,
subprocess.Popen(env=os.environ.copy())snapshots the parent's environment. The parent process updatesos.environ["DATABRICKS_TOKEN"]on rotation, but the child bash process (and anything launched from it) never sees the update.OpenCode caches credentials at startup — OpenCode reads
~/.local/share/opencode/auth.jsononce when launched and holds the token in memory for the lifetime of the TUI process. Even thoughcli_auth._update_opencode()writes the new token to disk every rotation, OpenCode never re-reads it.Content-filter proxy forwards stale auth headers — The proxy at
localhost:4000(which all OpenCode traffic passes through) copies theAuthorizationheader from OpenCode and forwards it verbatim to Databricks. Since OpenCode sends the stale token, the proxy sends the stale token.When PAT rotation runs (
pat_rotator._rotate_once()), it:/api/2.0/token/deleteos.environ,~/.databrickscfg, and all CLI auth files on diskThe revocation is what makes this fatal — the old token doesn't just expire naturally, it's immediately invalidated. OpenCode's next API call hits a 401.
Affected Components
~/.databrickscfg~/.claude/settings.jsonauth.json+ env varFix
PR #105 — Make the content-filter proxy read the current token from
~/.databrickscfg(which the PAT rotator always keeps current) and override theAuthorizationheader before forwarding to Databricks. 30-second file read cache to avoid per-request I/O.This is the right layer to fix it because:
.databrickscfgis the canonical token source, always updated by the rotator