Skip to content

feat: add Anthropic WIF : Workload Identity Federation auth#20073

Open
leprincep35700 wants to merge 1 commit into
NousResearch:mainfrom
leprincep35700:feat/anthropic-wif-auth
Open

feat: add Anthropic WIF : Workload Identity Federation auth#20073
leprincep35700 wants to merge 1 commit into
NousResearch:mainfrom
leprincep35700:feat/anthropic-wif-auth

Conversation

@leprincep35700

@leprincep35700 leprincep35700 commented May 5, 2026

Copy link
Copy Markdown
Contributor

Summary

I added Anthropic Workload Identity Federation (WIF) support as a first-class auth mode on the existing anthropic provider.

This keeps Hermes' provider model unchanged (provider=anthropic) while allowing Anthropic credentials to be resolved from a short-lived OIDC workload identity token instead of a static API key.

What changed

  • Added hermes auth add anthropic --type wif.
  • Added the interactive Anthropic auth choice:
    • API key
    • OAuth login
    • Workload Identity Federation (OIDC / short-lived workload tokens)
  • Persist WIF configuration in the Anthropic provider state instead of storing exchanged access tokens as long-lived credentials.
  • Resolve Anthropic WIF at runtime by exchanging the configured identity token file for a short-lived Anthropic access token.
  • Force WIF-issued Anthropic access tokens through the standard Bearer authorization header instead of x-api-key.
  • Preserve WIF/Bearer mode through runtime provider resolution, client rebuilds, cron, gateway, TUI, one-shot, ACP, and delegation/subagent paths.
  • Prefer an explicit Anthropic WIF configuration over stray ambient ANTHROPIC_API_KEY values, so a stale local API key cannot silently override a configured WIF setup.
  • Surface WIF in hermes auth even though it is provider-state-backed rather than credential-pool-backed.
  • Allow hermes auth remove anthropic anthropic-wif / indexed removal to remove the WIF configuration cleanly.
  • Add validation warnings when the configured identity token file is missing, empty, or does not look like a JWT. This helps catch the common mistake of passing a GitHub Actions workflow YAML file instead of the short-lived OIDC token file generated at runtime.
  • Add a README user-facing note covering Anthropic WIF setup, identity token file expectations, and backwards compatibility.

Why this shape

Anthropic WIF is not a separate model provider. It is another way to obtain Anthropic credentials. For that reason I kept the runtime on the existing Anthropic Messages path and made WIF an auth type under anthropic.

The exchanged Anthropic token is short-lived and should not be treated like a static API key or stored in the credential pool. Hermes stores the federation configuration and resolves/exchanges the token when needed.

Existing Anthropic API-key and OAuth setups continue to work unchanged. WIF is opt-in through the new Anthropic auth choice / --type wif path.

If a long-running Hermes process needs to rebuild the Anthropic client or re-resolve credentials, the runtime preserves forced Bearer/WIF semantics instead of falling back to API-key semantics.

Testing / verification

Latest local verification after replaying this branch cleanly on current upstream main (26933c2f5) and force-pushing the refreshed PR head (fbfdd237a):

HERMES_HOME=$(mktemp -d /tmp/hermes-wif-test-home.XXXXXX) HERMES_CONFIG_DIR="$HERMES_HOME" /opt/venv/bin/python -m py_compile   agent/anthropic_adapter.py   hermes_cli/auth.py   hermes_cli/auth_commands.py   hermes_cli/main.py   hermes_cli/runtime_provider.py   hermes_cli/web_server.py   run_agent.py   gateway/run.py   cli.py   tui_gateway/server.py   tools/delegate_tool.py   tools/process_registry.py   cron/scheduler.py   hermes_cli/oneshot.py   scripts/release.py

# Same targeted suite as before, split to avoid touching the live state.db:
/opt/venv/bin/python -m pytest tests/agent/test_bedrock_1m_context.py tests/agent/test_unsupported_parameter_retry.py -q -o addopts=
/opt/venv/bin/python -m pytest tests/tools/test_delegate.py::TestDelegationCredentialResolution tests/hermes_cli/test_auth_commands.py tests/hermes_cli/test_anthropic_provider_persistence.py tests/hermes_cli/test_runtime_provider_resolution.py -q -o addopts=
/opt/venv/bin/python -m pytest tests/agent/test_anthropic_adapter.py tests/cli/test_cli_provider_resolution.py -q -o addopts=
/opt/venv/bin/python -m pytest tests/run_agent/test_run_agent.py -q -o addopts=

Result:

py_compile: passed
21 passed in 3.88s
179 passed in 30.50s
174 passed in 18.65s
327 passed in 313.71s
Total targeted suite: 701 passed

GitHub checks are running on the refreshed head. I am not claiming full green CI until those complete.

Live WIF validation

I validated the real WIF path with a private GitHub Actions workflow on my fork using GitHub Actions OIDC as the identity provider:

GitHub Actions OIDC JWT -> Anthropic WIF token exchange -> Anthropic Messages API

The validation covered the previously problematic hermes chat path after the runtime fixes. Temporary diagnostic workflow/run artifacts were removed from my fork after validation so the PR does not depend on public diagnostic logs.

Notes for maintainers

This implementation follows Anthropic/Claude's Workload Identity Federation model as documented in the Claude Code IAM documentation and the Anthropic OAuth token exchange API docs:

If you want to reproduce the live WIF test, you need an Anthropic organization with Workload Identity Federation enabled and a federation rule configured for your OIDC issuer.

For GitHub Actions OIDC, the important pieces are:

  • permissions: id-token: write in the workflow
  • issuer URL: https://token.actions.githubusercontent.com
  • audience matching the workflow-requested audience, for example anthropic
  • a subject pattern matching the repository/branch that dispatches the workflow, for example:
    • repo:<owner>/<repo>:ref:refs/heads/main, or
    • a broader approved pattern such as repo:<owner>/<repo>:*
  • the workflow must write the short-lived OIDC JWT to a temporary file and pass that file to Hermes as identity_token_file

The identity token file must contain the runtime OIDC JWT. It should not be a workflow YAML file and it should never be committed or printed in logs.

If there are any questions about testing this end-to-end or about setting up the Anthropic/Claude-side WIF credential, please ask me. I can share the exact safe test workflow shape and the expected issuer/audience/subject checks without exposing tokens or secrets.

Security considerations

  • This PR does not store Anthropic WIF access tokens in the repo or credential pool.
  • The identity token file is treated as an external short-lived runtime input.
  • Test fixtures use fake placeholder values only.
  • WIF runtime calls use Bearer auth intentionally and avoid falling back to API-key semantics for WIF tokens.

Current status

Ready for review on the WIF/auth/runtime implementation.

I replayed the PR cleanly on current upstream main, force-pushed the cleaned branch to feat/anthropic-wif-auth, and verified the targeted WIF/auth/runtime suite locally with an isolated HERMES_HOME so the test run does not touch the live Hermes state database. GitHub checks are running on the refreshed head; I am not claiming full green CI until those finish.

This work was done with Hermes Agent.

@leprincep35700 leprincep35700 force-pushed the feat/anthropic-wif-auth branch from 42ed79f to 0d0434f Compare May 5, 2026 05:26
@leprincep35700 leprincep35700 marked this pull request as draft May 5, 2026 05:28
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have provider/anthropic Anthropic native Messages API area/auth Authentication, OAuth, credential pools comp/cli CLI entry point, hermes_cli/, setup wizard comp/agent Core agent loop, run_agent.py, prompt builder labels May 5, 2026
@leprincep35700 leprincep35700 force-pushed the feat/anthropic-wif-auth branch 8 times, most recently from 39019cc to a1d96a3 Compare May 5, 2026 14:17
@leprincep35700

Copy link
Copy Markdown
Contributor Author

Small follow-up after reviewing the PR from a maintainer-readability angle:

  • I added a user-facing README note for Anthropic WIF setup.
  • I clarified that existing Anthropic API-key and OAuth setups continue to work unchanged; WIF is opt-in via hermes auth add anthropic --type wif / the new interactive auth choice.
  • I documented that identity_token_file must be a short-lived runtime JWT, not a workflow YAML file.
  • I also clarified the long-running runtime behavior: when Hermes rebuilds or re-resolves the Anthropic client, it preserves forced Bearer/WIF auth semantics instead of falling back to API-key semantics.

If maintainers want to test this against an Anthropic WIF setup, please ask me — I can share the safe GitHub Actions workflow shape and the exact issuer/audience/subject checks without exposing tokens or secrets.

@leprincep35700 leprincep35700 marked this pull request as ready for review May 5, 2026 14:31
@leprincep35700

Copy link
Copy Markdown
Contributor Author

Validation update on the Anthropic WIF PR:

  • Local validation on the PR branch is still good:
    • python -m py_compile on the touched WIF/runtime files: OK
    • pytest tests/hermes_cli/test_auth_commands.py tests/hermes_cli/test_anthropic_provider_persistence.py tests/hermes_cli/test_runtime_provider_resolution.py -q -o addopts=166 passed
    • pytest tests/cli/test_cli_provider_resolution.py -q -o addopts=20 passed
  • I pushed two follow-up fixes onto feat/anthropic-wif-auth:
    • 8cab890 fix: preserve anthropic WIF bearer flag in chat route
    • f876d6f fix: pass CLI target model into runtime resolution
  • Live GitHub Actions WIF validation still shows a remaining Hermes CLI E2E problem:

What is now proven by the live run:

  • GitHub OIDC mint succeeds
  • Anthropic WIF resolution succeeds
  • direct AIAgent(..., anthropic_force_bearer_auth=True) succeeds
  • direct Anthropic message call succeeds (agent_direct_message_ok: True)
  • the CLI regression fix does preserve anthropic_force_bearer_auth in the routed runtime and the CLI now passes target_model into provider resolution

What still fails:

  • the Hermes auth WIF and chat E2E step is still red in GitHub Actions
  • the latest diagnostics narrowed the remaining failure further: after a successful direct resolve_runtime_provider(requested="anthropic", target_model="claude-sonnet-4-5"), a subsequent HermesCLI._ensure_runtime_credentials() in the same CI step still returns HTTP Error 401: Unauthorized

So the original route-propagation bug was real and is now fixed locally, but there is still at least one more runtime-resolution / repeated-WIF-resolution issue left in the live CLI path before I can honestly call Hermes chat fully green end-to-end.

I’m leaving this update here so reviewers can see the exact validated boundary:

  • WIF auth path to Anthropic: validated
  • direct Hermes AIAgent path with forced bearer auth: validated
  • full hermes chat CLI E2E in CI: not fully green yet

@leprincep35700

Copy link
Copy Markdown
Contributor Author

Quick status update from my side:

I moved this PR back to draft because I spent real Anthropic credits to test it end to end, and I want to keep the review state honest until the final Hermes CLI path is fully green.

What is validated so far:

  • GitHub OIDC mint works
  • Anthropic WIF exchange works
  • direct Hermes AIAgent WIF calls work
  • local targeted tests are green

What I just pushed:

  • 1660a36 fix: cache anthropic WIF token exchange per assertion

Why this change:

  • the live diagnostics strongly suggested that repeated WIF exchanges with the same short-lived GitHub OIDC assertion inside the same process were part of the remaining failure mode
  • this patch reuses a still-valid exchanged Anthropic access token for the same assertion/config instead of immediately re-exchanging it again

Targeted verification I ran locally:

  • pytest tests/agent/test_anthropic_adapter.py tests/cli/test_cli_provider_resolution.py tests/hermes_cli/test_runtime_provider_resolution.py -q -o addopts=281 passed
  • pytest tests/hermes_cli/test_auth_commands.py tests/hermes_cli/test_anthropic_provider_persistence.py tests/hermes_cli/test_runtime_provider_resolution.py -q -o addopts=166 passed

I am keeping it in draft until I rerun the live GitHub Actions WIF workflow and confirm the final hermes chat path is green end to end.

@leprincep35700 leprincep35700 marked this pull request as draft May 6, 2026 08:38
@leprincep35700 leprincep35700 marked this pull request as ready for review May 6, 2026 10:59
@leprincep35700

Copy link
Copy Markdown
Contributor Author

Final update: I’m moving this PR back to ready for review.

I validated the Anthropic WIF path end to end with a live GitHub Actions OIDC run using real Anthropic credits. The validation covered the previously failing CLI path, including Hermes auth WIF and chat E2E, and it passed after the latest fixes.

I also removed the temporary diagnostic workflow/run artifacts from my fork after validation so the PR does not depend on public diagnostic logs.

Targeted local validation passes:

  • tests/agent/test_anthropic_adapter.py
  • tests/cli/test_cli_provider_resolution.py
  • tests/hermes_cli/test_runtime_provider_resolution.py
  • tests/hermes_cli/test_auth_commands.py
  • tests/hermes_cli/test_anthropic_provider_persistence.py

Result: 337 passed

The WIF implementation has now been validated from auth setup through an actual hermes chat response, not just through the lower-level token exchange or SDK path. Existing Anthropic API-key/OAuth users remain unchanged; WIF is opt-in.

One note for reviewers: the PR branch still shows a general upstream Tests / test check as red in GitHub’s check rollup, but the dedicated WIF live validation and the targeted local regression suite above are green.

@leprincep35700

Copy link
Copy Markdown
Contributor Author

Quick status clarification after rebasing/updating this PR against the current upstream main:

  • The WIF/auth/runtime-focused validation is green locally: 353 passed across the Anthropic adapter, auth commands, provider persistence, runtime provider resolution, Bedrock/Anthropic beta behavior, unsupported-parameter retry handling, and delegation credential-resolution coverage.
  • Current PR checks are green for attribution, lint (ruff + ty diff), supply-chain audit, Nix on ubuntu/macos, and Tests / e2e.
  • The remaining red check is the broad Tests / test job.

I do not want to overclaim this as full green CI while that broad job is red. I checked recent upstream/main and other open PR runs, and the same broad-suite failure families are showing up outside this WIF branch too (cron MCP init, gateway platform config, browser Chromium checks, delegate heartbeat timing, credential-pool env fallback, sandbox cwd assertions, etc.). That makes this look like current upstream-wide CI noise rather than a WIF-specific failure.

So the intended review posture is:

  • ready for review on the WIF/auth/runtime implementation;
  • targeted WIF validation is green;
  • broad Tests / test is still red and called out honestly here and in the PR body;
  • happy to follow up if maintainers want that broad-suite noise split out or triaged separately.

@leprincep35700

Copy link
Copy Markdown
Contributor Author

Hi @teknium1, sorry for the ping — this PR adds Anthropic WIF as an opt-in auth mode. Targeted WIF validation is green, and the remaining broad test failure appears to match current upstream CI noise. Would you be the right person to review the auth/provider shape, or should I route it elsewhere?

@leprincep35700 leprincep35700 changed the title feat: add Anthropic Workload Identity Federation auth feat: add Anthropic WIF : Workload Identity Federation auth May 10, 2026
@leprincep35700 leprincep35700 force-pushed the feat/anthropic-wif-auth branch 3 times, most recently from 7067ad9 to fbfdd23 Compare May 14, 2026 16:13
@leprincep35700 leprincep35700 force-pushed the feat/anthropic-wif-auth branch 2 times, most recently from 7e7253c to 81ae5e5 Compare May 18, 2026 20:49
@leprincep35700 leprincep35700 force-pushed the feat/anthropic-wif-auth branch from 81ae5e5 to 67477f0 Compare May 26, 2026 07:40
@leprincep35700

Copy link
Copy Markdown
Contributor Author

Branch refreshed onto current main; WIF conflicts are resolved while preserving the newer Nous Portal README section, provider timeout/native Anthropic initialization, oneshot fallback model handling, and the WIF Bearer-auth propagation.

  • New head: 67477f0d1
  • Local validation rerun with isolated Hermes state:
    • /opt/venv/bin/python -m py_compile agent/anthropic_adapter.py hermes_cli/auth.py hermes_cli/auth_commands.py hermes_cli/main.py hermes_cli/runtime_provider.py hermes_cli/web_server.py run_agent.py gateway/run.py cli.py tui_gateway/server.py tools/delegate_tool.py tools/process_registry.py cron/scheduler.py hermes_cli/oneshot.py scripts/release.py
    • /opt/venv/bin/python -m pytest tests/agent/test_bedrock_1m_context.py tests/agent/test_unsupported_parameter_retry.py -q -o addopts=19 passed
    • /opt/venv/bin/python -m pytest tests/tools/test_delegate.py::TestDelegationCredentialResolution tests/hermes_cli/test_auth_commands.py tests/hermes_cli/test_anthropic_provider_persistence.py tests/hermes_cli/test_runtime_provider_resolution.py -q -o addopts=205 passed
    • /opt/venv/bin/python -m pytest tests/agent/test_anthropic_adapter.py tests/cli/test_cli_provider_resolution.py -q -o addopts=177 passed
    • /opt/venv/bin/python -m pytest tests/run_agent/test_run_agent.py -q -o addopts=346 passed
    • git diff --check

Total targeted local validation rerun: 747 passed. Fresh GitHub checks are running on the refreshed head, so I am not claiming full green CI until they finish.

@leprincep35700

Copy link
Copy Markdown
Contributor Author

Current-main reassessment:

I rechecked this against current main and the newer auth/provider-runtime changes.

Conclusion: the feature remains useful, but this branch should not be merged as-is.

What current main still lacks:

  • I did not find equivalent Anthropic Workload Identity Federation support.
  • Current main has Anthropic OAuth / Claude Code / Bearer-auth-adjacent work, but not the full WIF flow: federation rule/org/service-account config, identity-token-file exchange, WIF token caching, and WIF-specific CLI auth UX.

Current update status:

  • The branch is stale and conflicts with current main in auth/runtime-adjacent files.
  • The conflict is not just mechanical; the surrounding Anthropic/provider-resolution stack has changed enough that this needs a real rebase/reintegration pass.

Recommendation:

  • Keep the concept, but rework/rebase before review.
  • Salvage the WIF core pieces (config/env shape, token exchange, short-lived cache, Bearer-auth forcing, CLI auth UX) and reintegrate them with the current provider resolution / credential pool / OAuth / delegate paths and updated tests.

@leprincep35700 leprincep35700 force-pushed the feat/anthropic-wif-auth branch 2 times, most recently from cf2141f to 089a89a Compare June 1, 2026 09:13
@leprincep35700

Copy link
Copy Markdown
Contributor Author

Rebased onto current main and resolved the current auth/runtime conflicts.

  • New head: 089a89a1d
  • Conflict resolution kept the WIF Bearer-auth propagation through the current Anthropic/provider runtime paths and adapted the process-registry Windows guard to the newer code.
  • Local validation:
    • /opt/venv/bin/python -m pytest tests/agent/test_anthropic_adapter.py tests/hermes_cli/test_anthropic_provider_persistence.py tests/hermes_cli/test_auth_commands.py tests/hermes_cli/test_runtime_provider_resolution.py tests/cli/test_cli_provider_resolution.py tests/tools/test_delegate.py -q -o addopts='' --tb=short502 passed
    • /opt/venv/bin/python -m py_compile agent/agent_init.py agent/agent_runtime_helpers.py agent/anthropic_adapter.py agent/auxiliary_client.py cli.py cron/scheduler.py gateway/run.py hermes_cli/auth.py hermes_cli/auth_commands.py hermes_cli/main.py hermes_cli/oneshot.py hermes_cli/runtime_provider.py hermes_cli/web_server.py run_agent.py tools/delegate_tool.py tools/process_registry.py tui_gateway/server.py → OK
    • git diff --check → OK
  • Attribution was refreshed to the mapped GitHub noreply author email.

@leprincep35700 leprincep35700 force-pushed the feat/anthropic-wif-auth branch from 089a89a to 020d06d Compare June 6, 2026 06:42
@leprincep35700 leprincep35700 force-pushed the feat/anthropic-wif-auth branch from 020d06d to 6191eef Compare June 9, 2026 10:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/agent Core agent loop, run_agent.py, prompt builder comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have provider/anthropic Anthropic native Messages API type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants