Skip to content

Commit 702322c

Browse files
cameron-mcateerstainless-app[bot]
authored andcommitted
feat(bedrock): use auth header for mantle client (#734)
1 parent 1b7e4a5 commit 702322c

3 files changed

Lines changed: 29 additions & 16 deletions

File tree

bedrock/bedrockmantle.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ func mantleResolveParams() awsauth.ResolveParams {
109109
EnvBaseURL: "ANTHROPIC_BEDROCK_MANTLE_BASE_URL",
110110
DeriveBaseURL: func(region string) string { return fmt.Sprintf("https://bedrock-mantle.%s.api.aws/anthropic", region) },
111111
ServiceName: mantleServiceName,
112+
UseBearerAuth: true,
112113
}
113114
}
114115

bedrock/bedrockmantle_test.go

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,11 @@ func TestMantleAPIKeyModeHeaders(t *testing.T) {
123123
})
124124
sendTestMantleRequest(t, client)
125125

126-
if got := captured.Headers.Get("X-Api-Key"); got != "my-api-key" {
127-
t.Errorf("expected x-api-key %q, got %q", "my-api-key", got)
126+
if got := captured.Headers.Get("Authorization"); got != "Bearer my-api-key" {
127+
t.Errorf("expected Authorization %q, got %q", "Bearer my-api-key", got)
128128
}
129-
if captured.Headers.Get("Authorization") != "" {
130-
t.Error("expected no Authorization header in API key mode")
129+
if captured.Headers.Get("X-Api-Key") != "" {
130+
t.Error("expected no X-Api-Key header in bearer auth mode")
131131
}
132132
}
133133

@@ -200,8 +200,8 @@ func TestMantleAPIKeyFallbackToAWSEnv(t *testing.T) {
200200
client, captured := newTestMantleClient(t, MantleClientConfig{})
201201
sendTestMantleRequest(t, client)
202202

203-
if got := captured.Headers.Get("X-Api-Key"); got != "aws-fallback-key" {
204-
t.Errorf("expected x-api-key %q (AWS fallback), got %q", "aws-fallback-key", got)
203+
if got := captured.Headers.Get("Authorization"); got != "Bearer aws-fallback-key" {
204+
t.Errorf("expected Authorization %q (AWS fallback), got %q", "Bearer aws-fallback-key", got)
205205
}
206206
}
207207

@@ -213,8 +213,8 @@ func TestMantleAPIKeyMantleEnvOverridesAWSEnv(t *testing.T) {
213213
client, captured := newTestMantleClient(t, MantleClientConfig{})
214214
sendTestMantleRequest(t, client)
215215

216-
if got := captured.Headers.Get("X-Api-Key"); got != "mantle-key" {
217-
t.Errorf("expected x-api-key %q (mantle-specific), got %q", "mantle-key", got)
216+
if got := captured.Headers.Get("Authorization"); got != "Bearer mantle-key" {
217+
t.Errorf("expected Authorization %q (mantle-specific), got %q", "Bearer mantle-key", got)
218218
}
219219
}
220220

@@ -314,8 +314,8 @@ func TestNewMantleClientMessages(t *testing.T) {
314314
})
315315
sendTestMantleRequest(t, client)
316316

317-
if got := captured.Headers.Get("X-Api-Key"); got != "test-key" {
318-
t.Errorf("expected x-api-key %q, got %q", "test-key", got)
317+
if got := captured.Headers.Get("Authorization"); got != "Bearer test-key" {
318+
t.Errorf("expected Authorization %q, got %q", "Bearer test-key", got)
319319
}
320320
}
321321

@@ -369,15 +369,15 @@ func TestMantleClientRequestOptionsOverrideInternal(t *testing.T) {
369369
t.Setenv("AWS_BEARER_TOKEN_BEDROCK", "")
370370
t.Setenv("ANTHROPIC_AWS_API_KEY", "")
371371

372-
// User-provided opts should override internal opts (e.g. override the API key header)
372+
// User-provided opts should override internal opts (e.g. override the Authorization header)
373373
client, captured := newTestMantleClient(t, MantleClientConfig{
374374
APIKey: "internal-key",
375375
AWSRegion: "us-east-1",
376-
}, option.WithAPIKey("override-key"))
376+
}, option.WithHeader("Authorization", "Bearer override-key"))
377377
sendTestMantleRequest(t, client)
378378

379-
if got := captured.Headers.Get("X-Api-Key"); got != "override-key" {
380-
t.Errorf("expected X-Api-Key %q (from RequestOption override), got %q", "override-key", got)
379+
if got := captured.Headers.Get("Authorization"); got != "Bearer override-key" {
380+
t.Errorf("expected Authorization %q (from RequestOption override), got %q", "Bearer override-key", got)
381381
}
382382
}
383383

@@ -447,6 +447,10 @@ func TestMantleDoesNotLeakAnthropicAPIKey(t *testing.T) {
447447
sendTestMantleRequest(t, client)
448448

449449
if got := captured.Headers.Get("X-Api-Key"); got != "" {
450-
t.Errorf("expected no x-api-key header when using SigV4, got %q", got)
450+
t.Errorf("expected no X-Api-Key header when using SigV4, got %q", got)
451+
}
452+
// Authorization header should be SigV4, not Bearer
453+
if auth := captured.Headers.Get("Authorization"); !strings.HasPrefix(auth, "AWS4-HMAC-SHA256") {
454+
t.Errorf("expected SigV4 Authorization header, got %q", auth)
451455
}
452456
}

internal/awsauth/awsauth.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ type ResolveParams struct {
5858

5959
// ServiceName is the AWS service name used in SigV4 signing.
6060
ServiceName string
61+
62+
// UseBearerAuth, when true, sends the API key as an Authorization: Bearer header
63+
// instead of the default X-Api-Key header.
64+
UseBearerAuth bool
6165
}
6266

6367
// ResolvedConfig holds the fully resolved configuration after applying defaults and env vars.
@@ -253,7 +257,11 @@ func CreateClientOptions(ctx context.Context, cfg ClientConfig, params ResolvePa
253257
}
254258

255259
if resolved.APIKey != "" {
256-
opts = append(opts, option.WithAPIKey(resolved.APIKey))
260+
if params.UseBearerAuth {
261+
opts = append(opts, option.WithHeader("Authorization", "Bearer "+resolved.APIKey))
262+
} else {
263+
opts = append(opts, option.WithAPIKey(resolved.APIKey))
264+
}
257265
}
258266
if resolved.WorkspaceID != "" {
259267
opts = append(opts, option.WithHeader("anthropic-workspace-id", resolved.WorkspaceID))

0 commit comments

Comments
 (0)