cli: configure and launch with a custom OAuth app - #518
Draft
andy-xu-db wants to merge 1 commit into
Draft
Conversation
Completes the feature: `ug claude --oauth-client-id <id>` (and `ug codex`, bare `ug`, `ug configure`) signs in through a custom OAuth app and every agent it configures keeps minting from that same app. `configure_shared_state` persists the id *before* it authenticates, because the login and the gateway probe that follow both resolve the client id from the workspace entry. It follows the "None means inherit" convention already used by `use_pat` and `fable_enabled`, so a launch re-run keeps the workspace's app without repeating the flag; `--oauth-client-id ""` clears it and goes back to the built-in `databricks-cli` app. The generated configs *pin* the id rather than leaving it to run-time resolution. An agent runs its token helper as a bare command line, so the app has to be named in the command itself -- `state_oauth_client_id` reads it out of the state the writers already hold, for Claude's `apiKeyHelper`, Codex's `auth.args` (both current and legacy overlays), opencode's auth plugin, the registered `ucode mcp-proxy` argv, and both smart-routing hooks, which re-mint in their own processes. `_can_launch_from_cached_config` rejects an `--oauth-client-id` that disagrees with what the cached config was written against; reusing it would launch the agent with a token helper pointing at the other OAuth app. `doctor.py` and `smart_routing/v2.py` need no change: the former's `has_valid_databricks_auth` resolves the id from saved state by host, and the latter only reads the helper's executable path. Co-authored-by: Isaac <no-reply@databricks.com>
This was referenced Sep 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Completes the feature (the ticket's step 3):
ug claude --oauth-client-id <id>— andug codex, bareug, andug configure --oauth-client-id— signs in through a custom OAuth app, and every agent config it writes keeps minting from that same app.is what lands in Claude's
apiKeyHelperafterwards.Persisted before it authenticates.
configure_shared_statewrites the client id into the workspace's state ahead of the login and gateway probe that follow, because both resolve the id from that entry. It follows the "Nonemeans inherit" convention already used byuse_patandfable_enabled, so a launch re-run keeps the workspace's app without repeating the flag;--oauth-client-id ""clears it and goes back to the built-indatabricks-cliapp.Generated configs pin the id rather than leaving it to run-time resolution: an agent runs its token helper as a bare command line, so the app has to be named in the command itself.
state_oauth_client_idreads it out of the state the writers already hold, forapiKeyHelper,auth.args(current and legacy overlay),ucode mcp-proxyargv for every MCP client, andCache-bypass guard.
_can_launch_from_cached_configrejects an--oauth-client-idthat disagrees with what the cached config was written against — reusing it would launch the agent with a token helper pointing at the other OAuth app.doctor.pyandsmart_routing/v2.pyneed no change: the former'shas_valid_databricks_authresolves the id from saved state by host, and the latter only reads the helper's executable path. Claude'srelayedmode is also unaffected — it omitsapiKeyHelperentirely.Jira: AIGTWY-4550
Rollout note
The flag only selects the app; the 90-day TTL is a property of the app integration itself. A custom app integration is created with
refresh_token_ttl_in_minutes = 10080(7 days) by default, so it has to be set to129600on the integration for this to buy anything.Testing
uv run pytest— 2,349 passed, 38 skipped; the 21 failures areorigin/main's pre-existing ones (unchanged), so this PR adds 27 passing tests. Across the stack: 2,249 → 2,349 passing, same 21 failures at every level.uv run ruff check .,uv run ruff format --check src tests,uv run ty check src/.""clearing it, no inheritance across a workspace switch, the cached-config rejection, flag→configure forwarding for bothclaudeandcodex, and the pinned id in each generated config (state.jsonagent block, Claude settings, both Codex overlays, opencode plugin, MCP proxy argv, both routing hooks).🥞 Stacked PR
This pull request and its description were written by Isaac.