Skip to content

feat(webhooks): accept Authorization: AgentKey on forward routes - #402

Open
declan-scale wants to merge 1 commit into
mainfrom
declan-scale/agx1-833-agent-key-authorization-scheme
Open

feat(webhooks): accept Authorization: AgentKey on forward routes#402
declan-scale wants to merge 1 commit into
mainfrom
declan-scale/agx1-833-agent-key-authorization-scheme

Conversation

@declan-scale

@declan-scale declan-scale commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

🏆 Brought to you by the Golden Agent (Try it out)

Problem

The /agents/forward/... ingress today authenticates webhook requests via one of x-agent-api-key, GitHub X-Hub-Signature-256, a Slack signature, or an SGP principal through the auth gateway. Some webhook providers (Ironclad being the concrete driver) can only send a shared secret through the standard Authorization header and cannot set a custom header. Those requests currently fall through to SGP bearer verification and get rejected with 401, forcing customers to run a proxy solely to rewrite Authorization to x-agent-api-key.

Linear: AGX1-833.

Fix

Add a dedicated Authorization: AgentKey <agent-api-key> scheme on the forward ingress:

  • New helper extract_agent_key_from_authorization() in agent_api_keys_use_case.py parses the header. Scheme matching is case-insensitive per RFC 9110 § 11.6.1; Bearer, Basic, and any other scheme return None so they fall through to their existing branches — Bearer continues to hit the SGP auth gateway unchanged.
  • validate_agent_identity_headers now checks Authorization: AgentKey right after X-Agent-API-Key (and before GitHub/Slack/SGP), so a valid AgentKey request is never misrouted to bearer verification.
  • The DB lookup that verifies an external key is scoped to the agent in the URL is factored into a shared _verify_external_agent_api_key, so invalid, revoked, and wrong-agent keys produce the same 401 semantics whether the key arrived via X-Agent-API-Key or Authorization: AgentKey.
  • webhooks.md documents the new scheme with a curl example.

What I verified

  • Reviewed the staged diff for unused imports, comment noise, and shape consistency with the existing branches in validate_agent_identity_headers.
  • Prettier-formatted the changed markdown file (global prettier 2.8.8, matching the repo's pinned version).
  • Skipped yarn/ruff/pytest per the operator's validation policy — relying on CI for lint/typecheck/tests.

Test plan for reviewer

  • uv run pytest tests/unit/use_cases/test_agents_api_keys_use_case.py -q — new TestExtractAgentKeyFromAuthorization and TestValidateAgentIdentityHeadersAuthorizationScheme classes cover: valid, invalid, revoked (key deleted), wrong-agent, Bearer fallthrough, and regression for the existing X-Agent-API-Key path.
  • uv run ruff check src/domain/use_cases/agent_api_keys_use_case.py tests/unit/use_cases/test_agents_api_keys_use_case.py — the new helper and tests should pass repo lint.
  • Manual smoke against a local backend: POST /agents/forward/name/<agent>/<path> with Authorization: AgentKey <valid-external-key> returns 200; with a bogus/revoked/other-agent key returns 401; with Authorization: Bearer … behaves exactly as before.

Follow-ups / notes

  • The scheme name AgentKey matches the example in the Linear ticket; if a different name is preferred, only the module-level constant + docs need to change.
  • No changes to the SGP bearer path, GitHub signature, Slack signature, or x-agent-api-key header — those branches are byte-for-byte identical.

Greptile Summary

The PR adds an Authorization: AgentKey <key> authentication option for forwarded webhook routes while preserving existing bearer authentication and agent-scoped external-key validation.

  • Adds case-insensitive parsing for the dedicated AgentKey authorization scheme.
  • Reuses the existing external API-key lookup for both supported header transports.
  • Adds coverage for valid, invalid, revoked, cross-agent, bearer-fallback, and legacy-header behavior.
  • Documents the new authorization scheme and provides a curl example.

Confidence Score: 5/5

The PR appears safe to merge with no actionable correctness, security, or repository-rule issues identified.

The new scheme is parsed narrowly, preserves non-AgentKey authorization fallback, and uses the same exact agent-, key-, and type-scoped lookup as the existing external API-key path.

Important Files Changed

Filename Overview
agentex/src/domain/use_cases/agent_api_keys_use_case.py Adds narrow AgentKey parsing and routes extracted credentials through the existing agent-scoped external-key verifier without altering bearer fallback.
agentex/tests/unit/use_cases/test_agents_api_keys_use_case.py Adds parser and authentication-flow tests covering successful authentication, rejection cases, agent scoping, revocation, bearer fallback, and legacy behavior.
agentex/docs/docs/development_guides/webhooks.md Documents the AgentKey scheme, validation semantics, and an example webhook request using the Authorization header.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Forward webhook request] --> B{X-Agent-API-Key present?}
    B -->|Yes| C[Verify external key for URL agent]
    B -->|No| D{Authorization scheme is AgentKey?}
    D -->|Yes| C
    D -->|No| E{GitHub signature present?}
    E -->|Yes| F[Verify GitHub signature]
    E -->|No| G{Slack signature present?}
    G -->|Yes| H[Verify Slack signature]
    G -->|No| I{Auth gateway enabled?}
    I -->|Yes| J[Verify through auth gateway]
    I -->|No| K[Return missing-authentication response]
    C --> L{Agent-scoped external key exists?}
    L -->|Yes| M[Forward request to agent]
    L -->|No| N[Return 401]
    F --> M
    H --> M
    J --> M
Loading

Reviews (1): Last reviewed commit: "feat(webhooks): accept `Authorization: A..." | Re-trigger Greptile

Some webhook providers can only send a shared secret through the
standard `Authorization` header and cannot set a custom header such
as `x-agent-api-key`. Today those requests fall through to SGP
bearer verification and get rejected with 401, forcing customers to
run a proxy that rewrites the header.

Add a dedicated `AgentKey` `Authorization` scheme on `/agents/forward/...`
that validates the presented value as an external agent API key scoped
to the agent named in the URL. Invalid, revoked, and wrong-agent keys
return 401 identically to the existing `x-agent-api-key` path — the
underlying DB lookup is now shared between the two transports. `Bearer`
and every other scheme continue to fall through to the SGP auth
gateway, so existing flows are untouched.

Docs updated with an example curl for the new header.
@declan-scale
declan-scale requested a review from a team as a code owner August 11, 2026 18:20
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