feat: add OAuth support for Claude Code tokens

Add support for Claude Code OAuth tokens (sk-ant-oat01-*) in the Anthropic provider.

Claude Code generates OAuth tokens that require different authentication headers than standard Anthropic API keys:
- Standard API keys use: x-api-key header
- OAuth tokens require: Authorization: Bearer header + anthropic-beta: oauth-2025-04-20 header

Changes:
- Add isOAuthToken() to detect Claude Code OAuth tokens by sk-ant-oat01- prefix
- Update NewProviderWithBaseURL() to use proper headers for OAuth tokens
- Update Chat() method to handle OAuth tokens when using tokenSource

This implementation matches the approach used in zeroclaw (Rust implementation).

Fixes authentication errors when using Claude Code OAuth tokens:
- Before: "OAuth authentication is currently not supported"
- After: OAuth tokens work correctly with proper headers

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
omrikiei 2026-02-26 17:24:45 -06:00
parent 3584c0c7be
commit ba2b4da723

View file

@ -25,6 +25,11 @@ type (
const defaultBaseURL = "https://api.anthropic.com"
// isOAuthToken detects Claude Code OAuth tokens by their prefix
func isOAuthToken(token string) bool {
return strings.HasPrefix(strings.TrimSpace(token), "sk-ant-oat01-")
}
type Provider struct {
client *anthropic.Client
tokenSource func() (string, error)
@ -37,10 +42,22 @@ func NewProvider(token string) *Provider {
func NewProviderWithBaseURL(token, apiBase string) *Provider {
baseURL := normalizeBaseURL(apiBase)
client := anthropic.NewClient(
option.WithAuthToken(token),
option.WithBaseURL(baseURL),
var opts []option.RequestOption
// OAuth tokens (Claude Code) require special handling
if isOAuthToken(token) {
opts = append(opts,
option.WithHeader("Authorization", "Bearer "+token),
option.WithHeader("anthropic-beta", "oauth-2025-04-20"),
)
} else {
opts = append(opts, option.WithAuthToken(token))
}
opts = append(opts, option.WithBaseURL(baseURL))
client := anthropic.NewClient(opts...)
return &Provider{
client: &client,
baseURL: baseURL,
@ -77,8 +94,17 @@ func (p *Provider) Chat(
if err != nil {
return nil, fmt.Errorf("refreshing token: %w", err)
}
// OAuth tokens (Claude Code) require special handling
if isOAuthToken(tok) {
opts = append(opts,
option.WithHeader("Authorization", "Bearer "+tok),
option.WithHeader("anthropic-beta", "oauth-2025-04-20"),
)
} else {
opts = append(opts, option.WithAuthToken(tok))
}
}
params, err := buildParams(messages, tools, model, options)
if err != nil {