Skip to content

feat(auth): accept x-api-key header so Anthropic-native clients work (fixes #253)#315

Open
AloysJehwin wants to merge 2 commits into
mozilla-ai:mainfrom
AloysJehwin:feat/x-api-key-auth
Open

feat(auth): accept x-api-key header so Anthropic-native clients work (fixes #253)#315
AloysJehwin wants to merge 2 commits into
mozilla-ai:mainfrom
AloysJehwin:feat/x-api-key-auth

Conversation

@AloysJehwin

@AloysJehwin AloysJehwin commented Jul 18, 2026

Copy link
Copy Markdown

Summary

Anthropic SDK clients configured with ANTHROPIC_API_KEY send credentials as a bare x-api-key header (no Bearer prefix). Against otari these requests got a 401 on every route, making x-api-key the only thing standing between an Anthropic-native client and a working setup.

This PR adds x-api-key as a final fallback in _extract_bearer_token, after all existing header checks.

Changes

  • config.py — adds X_API_KEY_HEADER = "x-api-key" constant
  • deps.py_extract_bearer_token falls back to x-api-key (raw token, no Bearer prefix) before raising 401; Authorization: Bearer wins if both are present
  • main.pyx-api-key added to CORS allow_headers; XApiKeyAuth OpenAPI security scheme added alongside ApiKeyAuth
  • tests/unit/test_extract_bearer_token.py — 4 new cases: raw token extraction, Authorization precedence over x-api-key, canonical Otari-Key precedence, no-Bearer-prefix succeeds

Precedence (unchanged headers win)

Otari-Key > AnyLLM-Key/X-AnyLLM-Key > Authorization: Bearer > x-api-key

Decisions from issue #253

  1. Scope — global across all routes (smaller diff, consistent behaviour)
  2. Token format — raw token branch added separately from the Bearer path; no prefix stripping needed
  3. PrecedenceAuthorization wins over x-api-key if both are present

Checklist

  • lint (make lint) passes
  • typecheck (make typecheck) passes — 219 files clean
  • 14/14 unit tests pass (tests/unit/test_extract_bearer_token.py)

AI Usage

Drafted with Claude Code assistance; logic and test cases reviewed manually.

Summary

  • Added support for authenticating with the x-api-key header (for Anthropic-native clients), including a new shared constant for the header name.
  • Kept the existing authentication order, now with x-api-key used as the final fallback (after Otari-Key, AnyLLM-Key/X-AnyLLM-Key, and Authorization: Bearer).
  • Updated browser/CORS settings and OpenAPI security documentation to recognize x-api-key.
  • Added unit tests to verify correct token extraction, precedence rules, and handling of raw (non-Bearer-prefixed) values, using obviously fake tokens to avoid false positives.

Anthropic SDK clients send credentials as a bare x-api-key header with no
Bearer prefix. Previously _extract_bearer_token only read Otari-Key,
AnyLLM-Key/X-AnyLLM-Key aliases, and Authorization: Bearer <token>, so those
requests got a 401 at the on-ramp.

Changes:
- Add X_API_KEY_HEADER = "x-api-key" constant in config.py
- _extract_bearer_token falls back to x-api-key (raw, no Bearer prefix) after
  all existing header checks, before raising 401 — Authorization wins if both
  are present
- CORS allow_headers includes x-api-key for browser clients
- OpenAPI spec adds XApiKeyAuth security scheme alongside ApiKeyAuth
- 4 new tests in test_extract_bearer_token.py covering raw token extraction,
  precedence over x-api-key, and no-Bearer-prefix path

Closes mozilla-ai#253

Signed-off-by: Aloys Jehwin <aloysjehwin@gmail.com>
@github-actions github-actions Bot added the missing-template PR is missing required template sections label Jul 18, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ PR Template Missing

This PR appears to be missing required sections from the PR template.

Please edit your PR description to include the PR Type, Checklist, and AI Usage sections. The template helps maintainers review your contribution.

This PR will be automatically closed in 24 hours if the template is not restored.

If you're using an AI coding tool, please ensure it preserves the PR template.

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6cadcfa3-f736-4c10-ac1a-2dbadcb1d4cf

📥 Commits

Reviewing files that changed from the base of the PR and between 4adad0f and 98ba15e.

📒 Files selected for processing (1)
  • tests/unit/test_extract_bearer_token.py

Walkthrough

The gateway adds x-api-key authentication support, preserving existing header precedence, documenting the new security scheme in OpenAPI, allowing the header through CORS, and testing raw-token extraction behavior.

Changes

x-api-key authentication

Layer / File(s) Summary
Credential extraction and validation
src/gateway/core/config.py, src/gateway/api/deps.py, tests/unit/test_extract_bearer_token.py
Adds the x-api-key header constant, extracts its raw value, preserves existing precedence rules, and tests prefixed and unprefixed values.
API documentation and CORS wiring
src/gateway/main.py
Adds the XApiKeyAuth OpenAPI scheme, accepts it for non-public routes, and permits x-api-key in CORS requests.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers: peteski22

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title is relevant, but it uses feat(auth): instead of the required feat: prefix and exceeds the ~70-character target. Use feat: accept x-api-key header for Anthropic-native clients or similar, keeping the Conventional Commit prefix exact and the title shorter.
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The description covers the change, issue reference, checklist results, and AI usage, so it is mostly complete.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai
coderabbitai Bot requested a review from peteski22 July 18, 2026 17:16
Avoids GitGuardian false-positive on sk-ant-api03- prefix pattern.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/gateway/api/deps.py (1)

100-108: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Update the error message to include the new header.

Hi there! Great work adding the fallback for Anthropic clients. Just a small detail: since we now support the x-api-key header, we should probably mention it in this 401 error message so that clients know it's a valid authentication option. As per coding guidelines, we should raise explicit HTTPException instances with clear detail messages.

✨ Proposed tweak
     raw_token = request.headers.get(X_API_KEY_HEADER)
     if raw_token:
         return raw_token
 
     record_auth_failure("missing_credentials")
     raise HTTPException(
         status_code=status.HTTP_401_UNAUTHORIZED,
-        detail=f"Missing {API_KEY_HEADER} or Authorization header",
+        detail=f"Missing {API_KEY_HEADER}, Authorization, or {X_API_KEY_HEADER} header",
     )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/gateway/api/deps.py` around lines 100 - 108, Update the HTTPException
detail in the authentication fallback around raw_token to mention
X_API_KEY_HEADER alongside API_KEY_HEADER and Authorization, while preserving
the existing 401 status and failure-recording behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/gateway/api/deps.py`:
- Around line 100-108: Update the HTTPException detail in the authentication
fallback around raw_token to mention X_API_KEY_HEADER alongside API_KEY_HEADER
and Authorization, while preserving the existing 401 status and
failure-recording behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 532bdbca-8af1-4195-a4e4-45d9ad6d56dd

📥 Commits

Reviewing files that changed from the base of the PR and between 0c3542b and 4adad0f.

📒 Files selected for processing (4)
  • src/gateway/api/deps.py
  • src/gateway/core/config.py
  • src/gateway/main.py
  • tests/unit/test_extract_bearer_token.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

missing-template PR is missing required template sections

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant