Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/anthropic-client-custom-auth-header.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@effect/ai-anthropic": minor
---

Add `apiKeyHeader`, `apiKeyScheme`, and `headers` options to `AnthropicClient.make`/`layer`/`layerConfig`, allowing the API key header name (e.g. `authorization`), its auth scheme prefix (e.g. `Bearer`/`OAuth`), and arbitrary extra request headers to be customized. Useful when targeting a gateway or proxy in front of Anthropic's API that expects different authentication conventions.
114 changes: 111 additions & 3 deletions packages/ai/anthropic/src/AnthropicClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,30 @@ export const make: (options: {
*/
readonly apiKey?: Redacted.Redacted | undefined

/**
* The name of the HTTP header used to send the `apiKey`.
*
* Defaults to `"x-api-key"`, which is the header Anthropic's own API expects.
*
* Override this when targeting a gateway or proxy in front of Anthropic's
* API (or an Anthropic-compatible API) that authenticates requests using a
* different header, such as `"authorization"`.
*/
readonly apiKeyHeader?: string | undefined

/**
* The authentication scheme prefix to prepend to the `apiKey` value before
* it is sent in the `apiKeyHeader`, e.g. `"Bearer"` or `"OAuth"`.
*
* Defaults to `undefined`, which sends the raw `apiKey` value with no
* prefix (Anthropic's own API expects the raw key in `x-api-key`).
*
* Set this when `apiKeyHeader` is changed to `"authorization"` and the
* downstream service expects a scheme prefix, e.g. `"Bearer"` to produce
* an `authorization: Bearer <apiKey>` header.
*/
readonly apiKeyScheme?: string | undefined

/**
* The base URL endpoint used to communicate with Anthropic's API.
*
Expand Down Expand Up @@ -136,6 +160,18 @@ export const make: (options: {
*/
readonly anthropicVersion?: string | undefined

/**
* Additional HTTP headers to send with every request made by this client.
*
* Merged in after all standard headers (`apiKeyHeader`, `anthropic-version`,
* `accept`), so these values take precedence and may be used to override
* them if needed.
*
* Use this for headers required by a proxy or gateway sitting in front of
* Anthropic's API, such as additional authentication or routing headers.
*/
readonly headers?: Headers.Input | undefined

/**
* The organization ID to associate with API requests.
*
Expand Down Expand Up @@ -197,7 +233,7 @@ export const make: (options: {
never,
HttpClient.HttpClient | Scope.Scope
> = Effect.fnUntraced(function*(options) {
const apiKeyHeader = "x-api-key"
const apiKeyHeader = options.apiKeyHeader ?? "x-api-key"

yield* Effect.locallyScopedWith(Headers.currentRedactedNames, Arr.append(apiKeyHeader))

Expand All @@ -206,10 +242,16 @@ export const make: (options: {
request.pipe(
HttpClientRequest.prependUrl(options.apiUrl ?? "https://api.anthropic.com"),
options.apiKey
? HttpClientRequest.setHeader(apiKeyHeader, Redacted.value(options.apiKey))
? HttpClientRequest.setHeader(
apiKeyHeader,
options.apiKeyScheme
? `${options.apiKeyScheme} ${Redacted.value(options.apiKey)}`
: Redacted.value(options.apiKey)
)
: identity,
HttpClientRequest.setHeader("anthropic-version", options.anthropicVersion ?? "2023-06-01"),
HttpClientRequest.acceptJson
HttpClientRequest.acceptJson,
options.headers ? HttpClientRequest.setHeaders(options.headers) : identity
)
),
options.transformClient ? options.transformClient : identity
Expand Down Expand Up @@ -635,6 +677,28 @@ export const layer = (options: {
* using a mock server that doesn't require authentication).
*/
readonly apiKey?: Redacted.Redacted | undefined
/**
* The name of the HTTP header used to send the `apiKey`.
*
* Defaults to `"x-api-key"`, which is the header Anthropic's own API expects.
*
* Override this when targeting a gateway or proxy in front of Anthropic's
* API (or an Anthropic-compatible API) that authenticates requests using a
* different header, such as `"authorization"`.
*/
readonly apiKeyHeader?: string | undefined
/**
* The authentication scheme prefix to prepend to the `apiKey` value before
* it is sent in the `apiKeyHeader`, e.g. `"Bearer"` or `"OAuth"`.
*
* Defaults to `undefined`, which sends the raw `apiKey` value with no
* prefix (Anthropic's own API expects the raw key in `x-api-key`).
*
* Set this when `apiKeyHeader` is changed to `"authorization"` and the
* downstream service expects a scheme prefix, e.g. `"Bearer"` to produce
* an `authorization: Bearer <apiKey>` header.
*/
readonly apiKeyScheme?: string | undefined
/**
* The base URL endpoint used to communicate with Anthropic's API.
*
Expand Down Expand Up @@ -671,6 +735,17 @@ export const layer = (options: {
* differences.
*/
readonly anthropicVersion?: string | undefined
/**
* Additional HTTP headers to send with every request made by this client.
*
* Merged in after all standard headers (`apiKeyHeader`, `anthropic-version`,
* `accept`), so these values take precedence and may be used to override
* them if needed.
*
* Use this for headers required by a proxy or gateway sitting in front of
* Anthropic's API, such as additional authentication or routing headers.
*/
readonly headers?: Headers.Input | undefined
/**
* A function to transform the underlying HTTP client before it's used for API requests.
*
Expand Down Expand Up @@ -713,6 +788,28 @@ export const layerConfig = (options: {
* using a mock server that doesn't require authentication).
*/
readonly apiKey?: Config.Config<Redacted.Redacted | undefined> | undefined
/**
* The name of the HTTP header used to send the `apiKey`.
*
* Defaults to `"x-api-key"`, which is the header Anthropic's own API expects.
*
* Override this when targeting a gateway or proxy in front of Anthropic's
* API (or an Anthropic-compatible API) that authenticates requests using a
* different header, such as `"authorization"`.
*/
readonly apiKeyHeader?: Config.Config<string | undefined> | undefined
/**
* The authentication scheme prefix to prepend to the `apiKey` value before
* it is sent in the `apiKeyHeader`, e.g. `"Bearer"` or `"OAuth"`.
*
* Defaults to `undefined`, which sends the raw `apiKey` value with no
* prefix (Anthropic's own API expects the raw key in `x-api-key`).
*
* Set this when `apiKeyHeader` is changed to `"authorization"` and the
* downstream service expects a scheme prefix, e.g. `"Bearer"` to produce
* an `authorization: Bearer <apiKey>` header.
*/
readonly apiKeyScheme?: Config.Config<string | undefined> | undefined
/**
* The base URL endpoint used to communicate with Anthropic's API.
*
Expand Down Expand Up @@ -749,6 +846,17 @@ export const layerConfig = (options: {
* differences.
*/
readonly anthropicVersion?: Config.Config<string | undefined> | undefined
/**
* Additional HTTP headers to send with every request made by this client.
*
* Merged in after all standard headers (`apiKeyHeader`, `anthropic-version`,
* `accept`), so these values take precedence and may be used to override
* them if needed.
*
* Use this for headers required by a proxy or gateway sitting in front of
* Anthropic's API, such as additional authentication or routing headers.
*/
readonly headers?: Config.Config<Record<string, string> | undefined> | undefined
/**
* A function to transform the underlying HTTP client before it's used for API requests.
*
Expand Down