Skip to content

feat(ai-proxy): configurable credential attachment via auth field - #132

Merged
ndreno merged 1 commit into
mainfrom
feat/ai-proxy-auth-strategy
Jul 21, 2026
Merged

feat(ai-proxy): configurable credential attachment via auth field#132
ndreno merged 1 commit into
mainfrom
feat/ai-proxy-auth-strategy

Conversation

@ndreno

@ndreno ndreno commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Motivation

ai-proxy's Provider conflated two orthogonal concerns: the wire protocol (OpenAI Chat Completions/Responses vs Anthropic Messages) and the auth header convention. The credential header was hardcoded in three separate places (OpenAI transport, Anthropic transport, and the /v1/models aggregator), so any OpenAI-compatible upstream with a non-standard credential header could not be used without minting a new provider variant.

Concrete trigger: Brave AI Grounding exposes an OpenAI-compatible /v1/chat/completions surface (it even runs the agentic search loop server-side), but authenticates with X-Subscription-Token instead of Authorization: Bearer. Same story for Azure OpenAI (api-key).

What this does

Adds an auth field on targets, routes, and the flat config, decoupled from provider:

auth Effect
bearer Authorization: Bearer <key> (OpenAI/Ollama default)
api_key x-api-key: <key> (Anthropic default)
{ header: "Name" } arbitrary credential header
{ query: "param" } key in the query string
routes:
  - pattern: "brave-*"
    provider: openai
    base_url: "https://api.search.brave.com/res"
    api_key: "env://BRAVE_API_KEY"
    auth: { header: "X-Subscription-Token" }

When auth is omitted it defaults to the provider's convention, so existing configs are unchanged (fully backward compatible). The three hardcoded auth sites now share a single apply_auth helper, and custom auth is propagated through to the /v1/models aggregator (UpstreamProvider.auth) so discovery does not silently fail for such targets.

Changes

  • lib.rs: Auth enum, Provider::default_auth, TargetConfig::effective_auth, auth on TargetConfig/Route/flat config.
  • providers/mod.rs: unified apply_auth (single source of auth-attachment logic).
  • openai/anthropic transports + responses passthrough + models aggregator: all read apply_auth.
  • config-schema.json: Auth $def + property on the three surfaces; vacuum rulesets regenerated.
  • docs: dispatchers guide (config table, provider defaults, new "Custom credential headers" section), extensions reference; CHANGELOG entry.
  • Cargo.lock: local SDK path deps resynced 0.7.0 -> 0.8.1 (build side effect, unrelated to the feature).

Testing

  • 118 unit tests pass (8 new: Auth deserialization of both string and map forms, effective_auth provider defaults + explicit override, apply_auth for all four variants). Clippy clean (also fixed one pre-existing match_like_matches_macro warning in responses.rs).
  • End-to-end proof against a compiled .bca + running gateway (patched wasm), with a WireMock upstream emulating Brave:
    • model: brave-research -> outbound x-subscription-token: <key>, no Authorization
    • model: gpt-4o -> outbound Authorization: Bearer <key> (default preserved)
    • both compose to /res/v1/chat/completions via base_url

Note

Whether Brave's grounding endpoint ultimately wants Bearer or X-Subscription-Token is a config choice now covered either way; no code change is needed to switch.

`Provider` conflated two orthogonal concerns: the wire protocol (OpenAI
Chat Completions/Responses vs Anthropic Messages) and the auth header
convention. The credential header was hardcoded in three places (OpenAI
transport, Anthropic transport, and the `/v1/models` aggregator).

Add an `auth` field on targets, routes, and the flat config, decoupled
from `provider`:
- `bearer`            -> Authorization: Bearer <key>  (OpenAI/Ollama default)
- `api_key`          -> x-api-key: <key>              (Anthropic default)
- `{ header: "..." }` -> arbitrary credential header
- `{ query: "..." }`  -> key in the query string

When omitted, `auth` defaults to the provider's convention, so existing
configs are unchanged. This lets OpenAI-compatible endpoints with
non-standard credential headers (Brave AI Grounding `X-Subscription-Token`,
Azure OpenAI `api-key`) be configured without a dedicated provider type.

The three hardcoded auth sites now share a single `apply_auth` helper;
custom `auth` is also propagated to the `/v1/models` aggregator.

- lib.rs: `Auth` enum, `Provider::default_auth`, `TargetConfig::effective_auth`,
  `auth` on `TargetConfig`/`Route`/flat config
- providers/mod.rs: unified `apply_auth` (+ unit tests)
- openai/anthropic transports + responses passthrough + models aggregator
  read `apply_auth`
- config-schema.json: `Auth` def + property on the three surfaces;
  vacuum rulesets regenerated
- docs (dispatchers guide, extensions reference) + CHANGELOG

Cargo.lock: local SDK path deps resynced 0.7.0 -> 0.8.1 (build side effect).
@ndreno ndreno self-assigned this Jul 20, 2026
@ndreno
ndreno requested a review from marmeladema July 20, 2026 21:29
@ndreno
ndreno merged commit 1ed3baf into main Jul 21, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant