← stitchkitDocumentation

ADR 0072 — HTTP authorization precedes payload parsing

  • Status: Accepted — supersedes ADR 0004 while preserving its flat-hook design.
  • Date: 2026-08-14

Context

HTTP authorization used to share beforeHandle with application preconditions. That phase runs after query, JSON or multipart parsing so hooks can depend on validated input. It also meant a request that would ultimately be rejected for identity or scope could force the server to read and buffer its entire permitted payload first.

Moving all of beforeHandle earlier would reverse the problem: existing hooks would lose their validated input and multipart values. Authorization and post-validation preconditions therefore have different resource and data boundaries even when both happen before the handler.

Decision

The HTTP lifecycle has a dedicated authorize(context, endpoint) phase after route matching and path-parameter validation, but before the first query/body parse. Its AuthorizationContext contains request, URL-derived params, operation/trace/client metadata and deliberately exposes no payload-derived state.

Global authorization runs before route-group authorization. A rejection skips the remaining authorization, parsing, beforeHandle and handler phases while still travelling through canonical error normalization, CORS, logging and the single request-completion event.

beforeHandle keeps its post-validation meaning. createAuthHook is wired to HTTP authorize; MCP, Agent and CLI continue to wire the same policy to tool beforeHandle because those transports have already accepted and validated an input before the shared execution runner begins.

Alternatives rejected

  • Keep auth in beforeHandle: rejected uploads can still consume the full declared request budget before a 401 or 403.
  • Move beforeHandle wholesale before parsing: breaks valid input-dependent preconditions and weakens its typed contract.
  • Run the same hook in both phases: duplicates authentication, side effects and audit work while making order-dependent authorization bugs likely.
  • Parse only selected body fields before auth: requires trusting attacker-owned payload to decide whether the attacker may send that payload.

Consequences

  • HTTP auth hooks cannot depend on request payload; TypeScript reflects that boundary.
  • Path parameters remain available for scoped resource routing, and invalid path parameters fail before authentication work.
  • Consumers migrate one HTTP hook key with no compatibility alias.
  • Tool lifecycle remains transport-appropriate rather than pretending it can avoid input processing that already happened outside the HTTP dispatcher.