Skip to content

feat: support per-request API key for runtime inspection clients - #107

Draft
mevinmathew23 wants to merge 1 commit into
cisco-ai-defense:mainfrom
mevinmathew23:feat/per-request-api-key
Draft

feat: support per-request API key for runtime inspection clients#107
mevinmathew23 wants to merge 1 commit into
cisco-ai-defense:mainfrom
mevinmathew23:feat/per-request-api-key

Conversation

@mevinmathew23

Copy link
Copy Markdown

What

Adds an optional api_key argument to every runtime inspection method (Chat sync/async, HTTP, and MCP clients), allowing callers to override the API key on a per-request basis. Clients can also now be constructed without a key for purely per-request usage.

Why

The AI Defense API authenticates each call with an HTTP header (X-Cisco-AI-Defense-API-Key) stamped onto every request — the key is inherently per-request and not bound to a connection or session. The SDK, however, pinned the key at client construction (self.auth), forcing one client (and one connection pool) per key.

This is limiting for multi-tenant services and key-rotation scenarios, where a single shared client should be able to authenticate different calls with different keys without rebuilding the client or its connection pool each time. Per-request auth override is a well-established pattern (requests/httpx per-call headers=/auth=, Stripe's per-call api_key=).

How

Auth is now resolved per call via a small _resolve_auth(api_key) helper on the base inspection clients:

  • A per-request api_key takes precedence over the construction-time key.
  • When omitted, it falls back to the construction-time key (unchanged behavior).
  • When neither is available, it raises a clear ValidationError at call time.

The transport layer already accepted per-call auth, so no request-handler or auth-class changes were needed.

client = ChatInspectionClient(api_key=DEFAULT_KEY)
client.inspect_prompt("hi")                      # uses DEFAULT_KEY (unchanged)
client.inspect_prompt("hi", api_key=TENANT_KEY)  # per-request override

keyless = ChatInspectionClient()                 # no key at construction
keyless.inspect_prompt("hi", api_key=TENANT_KEY) # works

Backwards compatibility

Fully backwards compatible — all new parameters default to None and existing call sites are unaffected.

Tests

Adds tests/test_per_request_api_key.py covering per-call override, fallback, no-key construction, the no-key-anywhere error, and invalid-key validation, parameterized across the sync chat/HTTP/MCP clients plus the async chat client. Full existing suite remains green.

🤖 Generated with Claude Code

Allow callers to override the API key on individual inspection calls via
an optional api_key argument, and to construct a client without a key for
purely per-request usage. The key is an HTTP header stamped per request, so
this is a natural fit; previously the key was pinned at client construction.

Auth is now resolved per call: a per-request key takes precedence over the
construction-time key, falling back to it when omitted, and raising a clear
ValidationError when neither is available. Fully backwards compatible.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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