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:
parent
3584c0c7be
commit
ba2b4da723
1 changed files with 31 additions and 5 deletions
|
|
@ -25,6 +25,11 @@ type (
|
||||||
|
|
||||||
const defaultBaseURL = "https://api.anthropic.com"
|
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 {
|
type Provider struct {
|
||||||
client *anthropic.Client
|
client *anthropic.Client
|
||||||
tokenSource func() (string, error)
|
tokenSource func() (string, error)
|
||||||
|
|
@ -37,10 +42,22 @@ func NewProvider(token string) *Provider {
|
||||||
|
|
||||||
func NewProviderWithBaseURL(token, apiBase string) *Provider {
|
func NewProviderWithBaseURL(token, apiBase string) *Provider {
|
||||||
baseURL := normalizeBaseURL(apiBase)
|
baseURL := normalizeBaseURL(apiBase)
|
||||||
client := anthropic.NewClient(
|
|
||||||
option.WithAuthToken(token),
|
var opts []option.RequestOption
|
||||||
option.WithBaseURL(baseURL),
|
|
||||||
|
// 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{
|
return &Provider{
|
||||||
client: &client,
|
client: &client,
|
||||||
baseURL: baseURL,
|
baseURL: baseURL,
|
||||||
|
|
@ -77,8 +94,17 @@ func (p *Provider) Chat(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("refreshing token: %w", err)
|
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))
|
opts = append(opts, option.WithAuthToken(tok))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
params, err := buildParams(messages, tools, model, options)
|
params, err := buildParams(messages, tools, model, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue