Skip to content

broker: forward all client headers, only override the auth slot#133

Merged
dangtony98 merged 2 commits intomainfrom
feat/header-passthrough-default
Apr 26, 2026
Merged

broker: forward all client headers, only override the auth slot#133
dangtony98 merged 2 commits intomainfrom
feat/header-passthrough-default

Conversation

@dangtony98
Copy link
Copy Markdown
Contributor

@dangtony98 dangtony98 commented Apr 26, 2026

Closes #104.

Summary

  • Removes the 8-header allowlist (Content-Type, Content-Encoding, Accept, Accept-Encoding, Accept-Language, User-Agent, Idempotency-Key, X-Request-Id) that dropped non-allowlisted client headers on credentialed services. This was breaking upstreams that mandate vendor headers — most notably the Anthropic API (anthropic-version is required on every /v1/messages request).
  • Both ingress paths (/proxy and transparent MITM) now share a single denylist in ApplyInjection. Client headers flow through except for hop-by-hop (RFC 7230, now including Proxy-Connection), broker-scoped (X-Vault, Proxy-Authorization), the keys of inject.Headers (the auth slot for the configured auth type), and any names passed via extraStrip (the ingress's session-token header).
  • Pre-stripping inject.Headers keys from the copy loop is what preserves the injected always wins invariant — same outcome as the old allowlist approach, derived from data instead of a hardcoded list.
  • InjectResult.Passthrough is removed (vestigial after dispatch unified). res.Headers == nil is the new passthrough signal.

Approach vs. the issue's suggested fix

#104 suggested a per-service extra_passthrough_headers opt-in. This PR takes the inverse approach: forward everything by default, since header policy is a separate concern the broker had implicitly taken on, and the credential-brokering role only requires control over the headers the broker is itself injecting. A permissive default is the flexible foundation; restrictive opt-ins (strip_headers, allow_headers) can be added later if real customer need surfaces. The reverse is not true.

Behavior delta

  • Loosening only. No request that succeeds today fails after this change.
  • anthropic-version, anthropic-beta, If-Match, Prefer, custom tracing/signing headers, etc. — now reach the upstream on every auth type.
  • Cookie now also flows through on credentialed services. Set-Cookie response stripping is unchanged, so upstream-set cookies still don't reach the client.
  • Schema unchanged: no new YAML fields, no per-service overrides.

Auth-slot stripping by auth type

Auth type Headers stripped from client Headers injected by broker
bearer Authorization Authorization: Bearer <token>
basic Authorization Authorization: Basic <b64>
api-key the header named in auth.header <auth.header>: <prefix><value>
custom each header in auth.headers map keys resolved values for those keys
passthrough none none

Test plan

  • go test ./... — full suite green, including new TestApplyInjection_* matrix and Test{MITM,Proxy}BearerForwardsArbitraryClientHeaders integration tests on both ingresses.
  • Manual end-to-end with Anthropic (the Add per-service custom-header passthrough for provider APIs that require non-standard headers (e.g., anthropic-version) #104 repro): bearer service for api.anthropic.com, real /v1/messages POST with anthropic-version: 2023-06-01. Expect 200 (today: 400 missing-version).
  • Confirm injected wins: same request with bogus client Authorization: Bearer wrong returns 200 — broker's stored credential shadows the client value on both /proxy and MITM ingresses.
  • Existing Test{Proxy,MITM}PassthroughForwards* integration tests pass without source changes.

Docs

Per CLAUDE.md lockstep: cmd/skill_cli.md, cmd/skill_http.md, docs/learn/services.mdx (new "Header forwarding" section), docs/learn/security.mdx, docs/agents/protocol.mdx, docs/index.mdx, docs/quickstart/custom-agent.mdx, docs/guides/connect-custom-agent.mdx, docs/reference/cli.mdx all updated. UI tooltip for the passthrough auth type rephrased to match.

🤖 Generated with Claude Code

Removes the 8-header allowlist that dropped non-allowlisted client
headers (anthropic-version, anthropic-beta, If-Match, vendor tracing
headers, ...) on credentialed services, breaking upstreams like the
Anthropic API that mandate vendor request headers.

Both ingress paths now use a single denylist in ApplyInjection: client
headers pass through except hop-by-hop (RFC 7230, now including
Proxy-Connection), broker-scoped (X-Vault, Proxy-Authorization), the
keys of inject.Headers (the auth slot for the configured auth type),
and any names in extraStrip. Pre-stripping inject.Headers keys before
the copy loop is what preserves the "injected always wins" invariant.

The schema is unchanged. Behavior is a strict loosening — no requests
that succeed today will fail. Cookie now also flows through on
credentialed services; Set-Cookie response stripping is unchanged.

InjectResult.Passthrough is removed (its only consumer was the dispatch
in ApplyInjection); res.Headers == nil is the new passthrough signal.
CopyPassthroughRequestHeaders is inlined and deleted.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Code review skipped — your organization's overage spend limit has been reached.

Code review is billed via overage credits. To resume reviews, an organization admin can raise the monthly limit at claude.ai/admin-settings/claude-code.

Once credits are available, reopen this pull request to trigger a review.

@mintlify
Copy link
Copy Markdown

mintlify Bot commented Apr 26, 2026

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
agent-vault 🟢 Ready View Preview Apr 26, 2026, 11:07 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@infisical-review-police
Copy link
Copy Markdown

💬 Discussion in Slack: #pr-review-agent-vault-133-broker-forward-all-client-headers-only-override-the-au

Posted by Review Police — reviews, comments, new commits, and CI failures will stream into this channel.

A proxy must treat any header named in the Connection field as
hop-by-hop for that connection. Pre-PR this was hidden by the
8-header allowlist; with all client headers now passing through, an
unhandled `Connection: X-Custom-Hop` would let X-Custom-Hop reach
the upstream. Honors the dynamic strip alongside the static
HopByHopHeaders set.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dangtony98 dangtony98 merged commit 7f53eec into main Apr 26, 2026
9 checks passed
@dangtony98 dangtony98 deleted the feat/header-passthrough-default branch April 26, 2026 23:23
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.

Add per-service custom-header passthrough for provider APIs that require non-standard headers (e.g., anthropic-version)

1 participant