# ADR-073: Door-Surface Basic Auth Tolerance (git / git-lfs Clients) ## Status Accepted ## Context Review 008 AH-1, from alkgit's LFS POC (POC-L): a real `git-lfs` 3.7.0 client authenticates the batch endpoint with **Basic** credentials (URL userinfo — the spec-shape behavior of the official client; config `http://user:pass@host/repo`). The shared identity middleware was Bearer-only — the module doc said so explicitly ("Bearer-only is the auth mechanism") — so a door mounted under the shared auth layer received the batch request with the middleware already having folded in `None`, and the door had to re-parse the `Authorization` header itself (Basic *or* Bearer) to get any identity. The middleware is shared by the gateway endpoints and `to_mcp`. Every HTTP-door surface whose real client authenticates with Basic (LFS today; git's smart-HTTP transport is tomorrow's `git` door) would silently re-implement the fallback locally — the quiet-bypass shape alkcall review 012 records for the ownership seam, one layer up in the same stack. ## Decision **Split the auth surface into token surfaces and the door surface, and teach the door surface Basic — through the same resolution backend, with no new `IdentityProvider` method.** - `bearer_auth_middleware` stays Bearer-only and continues to cover the token-auth surfaces: the gateway endpoints, `/openapi.json`, `/healthz`, and the `to_mcp` nest. A Basic header contributes no identity there. `/call`, `/batch`, `/subscribe`, `/publish`, `/mcp`, and the WS upgrade path are token surfaces — this is the "no blanket method" constraint: a Basic credential never gains identity anywhere the deployment has not explicitly set up for it. - `door_auth_middleware` (new) is applied by `build_router` to the extras-door router (`HttpAdapter::with_extra_routes`) — the surface legacy clients authenticate on. - Both middlewares resolve through `IdentityProvider::resolve_from_token()`. Basic parsing: `Basic base64(user:pass)` — the password field (the GitHub-PAT shape; the user segment is ignored) is decoded and fed as the `AuthToken` raw bytes. A colon-less value is treated as a bare password. No new trait method: the provider's grant table governs a Basic credential exactly as it governs the same credential presented as Bearer — and the same backend mechanism that grants privileges to tokens grants them to these credentials (SOCKS5 userinfo-style integrations can follow the same pattern later). - Fallback semantics unchanged: no header → `None`; unparseable or unresolvable credential → `None` (unauthenticated, not an error). A parse-time failure never becomes a 4xx of its own. - Doors may opt out with their own middleware stack as before ([ADR-046](046-assembly-layer-custom-http-routes.md) §4). ## Consequences **Positive:** - `git-lfs` / `git` doors work against a deployment whose provider maps password-tokens through `resolve_from_token`, with zero door-side header re-parsing. - Scoping is structural (per-middleware), not per-path-inspection: Basic tolerance exists only where the assembly layer mounted the door surface. **Negative:** - A door surface deployment that does *not* want its door credentials resolvable as Basic must now ensure the provider does not resolve those values as tokens — or opt the door out of the shared layer. - Scheme prefixes remain case-sensitive ("Bearer "/"Basic "), matching the pre-existing Bearer parsing; strictly RFC-noncompliant lowercase-scheme clients parse to `None`. ## References - [Review 008](../../reviews/008-http-door-consumer-review.md) — AH-1 evidence and disposition space - [ADR-004](004-auth-as-shared-core.md) — the shared-core resolution backend this rides - [ADR-046](046-assembly-layer-custom-http-routes.md) — the extras-door surface the door middleware covers (§4 amended; AH-2 static-route constraint recorded there) - alkcall review 012 — the same-round quiet-bypass analysis this avoids repeating at the door layer