feat(inbound-api): accept X-API-Key header as credential transport alongside Authorization: Bearer

This commit is contained in:
Joseph Doherty
2026-06-16 14:01:01 -04:00
parent 7362598b69
commit 510559e1be
2 changed files with 127 additions and 6 deletions
@@ -80,14 +80,19 @@ public static class EndpointExtensions
var routeHelper = httpContext.RequestServices.GetRequiredService<RouteHelper>();
var options = httpContext.RequestServices.GetRequiredService<IOptions<InboundApiOptions>>().Value;
// Auth re-arch (A+B): the inbound credential is now a Bearer token
// (Authorization: Bearer sbk_<keyId>_<secret>) verified by the shared
// ZB.MOM.WW.Auth.ApiKeys verifier — peppered-HMAC constant-time secret
// compare is handled inside the library verifier. The raw X-API-Key header
// and the in-repo ApiKeyValidator are retired on this path.
// Auth re-arch (A+B) + X-API-Key restore: the inbound credential is accepted
// from EITHER the Authorization header ("Bearer sbk_<keyId>_<secret>") OR the
// legacy "X-API-Key: sbk_<keyId>_<secret>" header (raw token). Both are passed
// to the SAME shared ZB.MOM.WW.Auth.ApiKeys verifier — the parser strips an
// optional "Bearer " prefix and otherwise accepts a bare token, so the
// peppered-HMAC constant-time secret compare is identical for both transports.
// Authorization takes precedence when both headers are present.
var authorizationHeader = httpContext.Request.Headers.Authorization.ToString();
var credential = !string.IsNullOrWhiteSpace(authorizationHeader)
? authorizationHeader
: httpContext.Request.Headers["X-API-Key"].ToString();
var verification = await verifier.VerifyAsync(
authorizationHeader, httpContext.RequestAborted);
credential, httpContext.RequestAborted);
if (!verification.Succeeded)
{