feat: If an `apiKey` is provided, skip Oauth handling.
Context
My situation is this:
- I have a personal Claude Code Pro subscription, which is Oauth-ed (just like Claude Code the agent does).
- My work uses Anthropic Claude Enterprise, with multiple API keys (one key for each client). Those are usually set in the config via
provider.anthropic.options.apiKey.
Using fake "profiles" (individually managed custom config files), I'd like to be able to use opencode with either type.
Expected
When configured to use the Anthropic Claude provider, if an (enterprise) apiKey is provided, it should take precedence over the stored Oauth (Claude Code Pro) credentials. If not provided, opencode should use the Oauth credentials.
Actual
Because of the way the configurations merging happens, the Oauth credentials (from ~/.local/share/opencode/auth.json) always "win", and the manually set apiKey is ignored.
This means all usage, even when I provide an enterprise API key, always ends up pointed at my personal Claude Pro subscription.
Solution
If an apiKey is configured & present, assume the user knows better & skip the loading of the Oauth credentials.
Deeper Explanation of Setup/Situation
- I'm simulating having different "profiles" (one-per-client + a personal) by creating a bunch of custom config files within
~/.config/opencode/my_profiles/<profile-name>.jsonc. - In the work-based config files, under the
provider.anthropic.options.apiKeypath, I supply{file:~/.secrets/<profile-name>.apikey}, with different key paths for each work config. - I then launch
opencodewith:OPENCODE_CONFIG=~/.config/opencode/my_profiles/<profile-name>.jsonc opencode. - (Assuming I've renamed/moved the
~/.local/share/opencode/auth.jsonaway) This works great for all the different clients/keys... but because that file is gone, I can no longer use my personal subscription (e.g.OPENCODE_CONFIG=~/.config/opencode/my_profiles/personal.jsonc opencode). - (Assuming I move the
~/.local/share/opencode/auth.jsonback) My personal Claude Pro subscription is back, but now takes over everything, & the client API keys are never used.
This adds a small skip (non-specific to Anthropic/Claude) to the provider code, only if an apiKey is set/present. It includes a new passing test that demonstrates the behavior.
Also, this may help with (or completely) resolve #4291.
/review
lgtm
hm im not sure this is proper fix, ik it prolly works but doesnt this skip all plugins that have auth in them? ik some people pass custom fetch implementations to their providers and this skips loading the plugin altogether i think
Ah, that's a good point. So from there, while still trying to solve this, I'd propose two options:
- Reorder the loading so that the plugins come first, before the
apiKey. Not sure that this will work, but I will give it a try. - Introduce a new configuration option. In looking through the schema, there only seems to be the top-level
plugins, with nothing under theprovider. So maybe: a. An explicitpluginslist underproviderorprovider.options(might be painful to keep in-sync long-term?) b. Adisabled_pluginslist underproviderorprovider.options(just disabling the specific Oauth pluginopencode-anthropic-authfor this instance, while not blocking other plugins) c. Anignore_oauthsetting covering this specific case.
Maybe there's a different approach I'm not seeing.