Skip to content

fix(web/tavily): authenticate via Authorization header, config-driven - #66599

Open
zivisaiah wants to merge 1 commit into
NousResearch:mainfrom
zivisaiah:fix/tavily-header-auth
Open

fix(web/tavily): authenticate via Authorization header, config-driven#66599
zivisaiah wants to merge 1 commit into
NousResearch:mainfrom
zivisaiah:fix/tavily-header-auth

Conversation

@zivisaiah

Copy link
Copy Markdown

What

The Tavily web provider sends the API key inside the JSON request body (payload["api_key"]). This change sends it as an Authorization: Bearer <key> header instead, and adds a TAVILY_AUTH_STYLE env var (header default, body for the legacy path) so nothing breaks for anyone relying on the old behavior.

Why

  1. Matches Tavily's current docs. Tavily's API reference now documents Bearer header auth as the standard method (Authorization: Bearer tvly-...). The in-body api_key field is legacy.

  2. Works behind a credential proxy. Some deployments route agent egress through a credential-injecting proxy that attaches the real key at the network edge so the bot never holds it. A proxy can rewrite request headers but not JSON request bodies, so body-only auth cannot be injected.

  3. Precedence matters, and body currently wins. I verified empirically against the live Tavily API: when a request carries both a placeholder api_key in the body and a valid key in the Authorization header, Tavily uses the body value and returns 401 Unauthorized. Header-only auth returns 200. So simply adding a header is not enough, the body key has to be dropped, which is what this patch does by default.

Changes

  • plugins/web/tavily/provider.py: _tavily_request sends the key as a Bearer header by default, or in the body when TAVILY_AUTH_STYLE=body. Backward compatible.

Testing

Header auth verified end to end against api.tavily.com (search returns real results). Legacy body mode preserves the prior request shape.

@alt-glitch alt-glitch added type/bug Something isn't working comp/plugins Plugin system and bundled plugins tool/web Web search and extraction area/config Config system, migrations, profiles P3 Low — cosmetic, nice to have sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Jul 18, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related to merged #24658: that was the older tools/web_tools.py /crawl-only header repair; this PR updates the current Tavily plugin provider and makes header auth the configurable default.

@tonydwb tonydwb 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.

Code Review Summary

Verdict: Comment

Critical

  • None

Warnings

  • None

Assessment

Fixes Tavily authentication to use Authorization: Bearer header (the documented method) with a config-driven fallback to legacy in-body api_key field. Header auth is the correct default as it allows upstream credential proxies to rewrite headers.

Looks Good

  • New TAVILY_AUTH_STYLE config option with documented values
  • Clean conditional: header vs body auth styles
  • Minimal diff, focused fix with no side effects
  • Good inline documentation

Reviewed by Hermes Agent

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for targeting the current Tavily plugin rather than the removed inline helper; plugins/web/tavily/provider.py:54-59 confirms main still sends api_key in the JSON body.

Problems

  • The new TAVILY_AUTH_STYLE at PR diff right line 61 is a non-secret behavioral environment variable. AGENTS.md:102-107 requires this class of setting to use config.yaml rather than .env.
  • The proxy-only claim is incomplete: plugins/web/tavily/provider.py:46-51 still rejects an unset TAVILY_API_KEY, and Tavily selection checks it at tools/web_tools.py:242,334-335.
  • The PR changes no tests. Existing coverage asserts body auth in tests/tools/test_web_tools_tavily.py:32-48; add mocked assertions for default header auth, no body key, and any retained compatibility path.

Suggested changes

  • Use a documented web config setting for legacy selection, or omit the legacy switch.
  • Define and test the proxy-only credential contract.

Automated hermes-sweeper review.

)

base_url = get_provider_env("TAVILY_BASE_URL") or "https://api.tavily.com"
auth_style = (get_provider_env("TAVILY_AUTH_STYLE") or "header").strip().lower()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

TAVILY_AUTH_STYLE is a user-facing, non-secret behavior switch. Please move any retained legacy-auth selection to a documented web config.yaml setting (or remove the compatibility mode); AGENTS.md:102-107 reserves .env for credentials.

@teknium1 teknium1 added the sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform label Jul 18, 2026
@GottZ

GottZ commented Aug 3, 2026

Copy link
Copy Markdown

This was generated by AI during triage.

Summary

Three open PRs modify the Tavily provider but address distinct causes: #32798 changes search-request defaults, #66599 changes API-key transport, and #67202 adds proxy routing. The complete diffs show adjacent changes rather than competing implementations.

Related pull requests

  • Fix/tavily provider api defaults #32798 related — (+3/-1) — n/a: The diff adds advanced search and image-request defaults, but no payload regression test or normalized image output; consistent with the contributor keep_open review, retain it with a salvage path that adds the test and resolves the image-output contract.
  • fix(web/tavily): authenticate via Authorization header, config-driven #66599 related — (+14/-2) — n/a: The diff moves authentication to a Bearer header with a legacy environment-variable switch; consistent with the contributor keep_open review, retain it with a salvage path that moves behavioral selection to config.yaml or removes the switch, defines the proxy-only credential contract, and tests every retained auth path.
  • feat(tavily): add WEB_SEARCH_PROXY env var support for proxy HTTP requests #67202 related — (+87/-1) — n/a: The diff adds config-driven Tavily proxy routing and configured/unset request tests, partially addressing the contributor keep_open review, but retains an untested WEB_SEARCH_PROXY behavioral fallback alongside the cited config.yaml policy; retain it with a salvage path that removes the fallback or explicitly resolves the policy and tests it.

Suggested consolidation

Keep #32798, #66599, and #67202 open with the distinct salvage paths identified by their contributor reviews. Their complete diffs address request defaults, authentication transport, and proxy routing respectively, so none is supported as a duplicate; author action is required on each remaining review concern.

Cross-PR triage: Reviewed 3 pull requests and 0 issues in this complex. Each diff was read against this issue; Assessment working set: 7 kB of PR diffs, 5 kB of issue/PR text, 4 kB of discussion (5 comments), 0 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.

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

Labels

area/config Config system, migrations, profiles comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades tool/web Web search and extraction type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants