feat: support config-driven OAuth endpoints on the claude client

- ClaudeConfig gains an oauth: block (custom endpoints, e.g. a private
  gateway); without it, auth: oauth keeps the stock Claude Pro/Max provider
- Claude-Code system-prefix spoof + anthropic-beta header are only sent on
  the stock provider path
- OAuth tokens are stamped with an issuer fingerprint (token_url|client_id)
  so switching endpoints never replays a token against the wrong issuer
- All auth flows refresh the in-memory access-token cache on save, so
  .authenticate mid-session takes effect immediately
- A custom oauth: block now requires api_base: refusing to silently fall
  back to api.anthropic.com prevents sending a gateway token to the wrong
  host
This commit is contained in:
Dark-Alex-17 committed 2026-09-15 23:51:51 -06:00
1 parent fcc0049ab2
commit 4cc5563ba8
4 files changed
+798 -31

No files matched your search

+14
View File
@@ -385,6 +385,20 @@ clients:
auth: null # When set to 'oauth', Coyote will use OAuth instead of an API key
# Authenticate with `coyote --authenticate` or `.authenticate` in the REPL
prompt_cache: true # Optional - enable Anthropic prompt caching (default: true)
# Optional: custom OAuth endpoints (e.g. a private gateway). Requires `auth: oauth` above.
# With `auth: oauth` and no `oauth:` block you get the stock Claude Pro/Max provider; adding
# `oauth:` switches to generic OAuth against your endpoints (the Claude-Code system-prefix
# and anthropic-beta header are not sent). An `oauth:` block makes `api_base` REQUIRED —
# Coyote refuses to fall back to api.anthropic.com with a gateway token.
# auth: oauth
# api_base: https://gateway.example/anthropic/v1
# oauth:
# client_id: '{{GATEWAY_CLIENT_ID}}'
# device_authorization_url: https://auth.gateway.example/oauth/device_authorization
# token_url: https://auth.gateway.example/oauth/token
# flow: device_code
# scopes: [claude.chat]
# resource: https://gateway.example/v1
# See https://docs.mistral.ai/
- type: openai-compatible