feat(webhooks): accept Authorization: AgentKey on forward routes - #402
Open
declan-scale wants to merge 1 commit into
Open
feat(webhooks): accept Authorization: AgentKey on forward routes#402declan-scale wants to merge 1 commit into
Authorization: AgentKey on forward routes#402declan-scale wants to merge 1 commit into
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🏆 Brought to you by the Golden Agent (Try it out)
Problem
The
/agents/forward/...ingress today authenticates webhook requests via one ofx-agent-api-key, GitHubX-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 standardAuthorizationheader and cannot set a custom header. Those requests currently fall through to SGP bearer verification and get rejected with401, forcing customers to run a proxy solely to rewriteAuthorizationtox-agent-api-key.Linear: AGX1-833.
Fix
Add a dedicated
Authorization: AgentKey <agent-api-key>scheme on the forward ingress:extract_agent_key_from_authorization()inagent_api_keys_use_case.pyparses the header. Scheme matching is case-insensitive per RFC 9110 § 11.6.1;Bearer,Basic, and any other scheme returnNoneso they fall through to their existing branches —Bearercontinues to hit the SGP auth gateway unchanged.validate_agent_identity_headersnow checksAuthorization: AgentKeyright afterX-Agent-API-Key(and before GitHub/Slack/SGP), so a validAgentKeyrequest is never misrouted to bearer verification._verify_external_agent_api_key, so invalid, revoked, and wrong-agent keys produce the same401semantics whether the key arrived viaX-Agent-API-KeyorAuthorization: AgentKey.webhooks.mddocuments the new scheme with acurlexample.What I verified
validate_agent_identity_headers.prettier2.8.8, matching the repo's pinned version).yarn/ruff/pytestper 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— newTestExtractAgentKeyFromAuthorizationandTestValidateAgentIdentityHeadersAuthorizationSchemeclasses cover: valid, invalid, revoked (key deleted), wrong-agent,Bearerfallthrough, and regression for the existingX-Agent-API-Keypath.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.POST /agents/forward/name/<agent>/<path>withAuthorization: AgentKey <valid-external-key>returns 200; with a bogus/revoked/other-agent key returns 401; withAuthorization: Bearer …behaves exactly as before.Follow-ups / notes
AgentKeymatches the example in the Linear ticket; if a different name is preferred, only the module-level constant + docs need to change.x-agent-api-keyheader — 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.AgentKeyauthorization scheme.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
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 --> MReviews (1): Last reviewed commit: "feat(webhooks): accept `Authorization: A..." | Re-trigger Greptile