acquia/http-hmac-php
PHP implementation of HTTP HMAC authentication for securing service-to-service API requests. Sign and verify requests using shared secrets, with support for PSR-7 and framework request objects, making it easy to add tamper-resistant authentication to PHP applications.
Architecture fit: acquia/http-hmac-php is a PSR-7 request/response signing library implementing the HTTP HMAC specification, not a Laravel package. There is no service provider, publishable config, facade, or artisan command, and nothing registers itself in the container. For a TPM this matters because it reframes the work item: adopting the package is not "install and configure," it is "add a dependency and build a thin integration layer we own." The natural seam is the outbound HTTP client — a Guzzle middleware in front of Http:: or a dedicated client factory instance — plus a verification middleware for inbound webhook or partner traffic. Fit is strong when the integration surface is a bounded, enumerated set of endpoints that mandate HMAC; it is a poor fit if stakeholders are expecting framework-native auth primitives, an OAuth token flow, or a drop-in Laravel guard.
Integration feasibility: High and cheap to prove. The runtime footprint is essentially psr/http-message ^1.0 || ^2.0 and ext-hash, both already satisfied by Laravel 9/10/11 with Guzzle 7. There is no database, queue, cache, migration, or config-publication step. The deliverable is a composer constraint bump, a signing middleware, a verification path, and — the part that usually gets under-scoped — shared-secret storage and rotation. A TPM can credibly frame this as a one-to-two-sprint item for a single engineer plus review, with a spike to confirm the middleware seam.
Technical risk: Low to moderate, and the risk profile is well-documented because 6.2.0 was an infrastructure release rather than a feature release. Concretely: minimum PHP moves 7.3 → 7.4; implicitly nullable parameters gained explicit ?Type hints to clear PHP 8.4 deprecations; suggested and dev dependencies moved forward (Guzzle ^7.0, laminas-diactoros ^2.2 || ^3.0, symfony/security-bundle ^5.4, psr-http-message-bridge ^2.1 || ^6.4 || ^7.0, PHPUnit ^9.6); CI moved off Travis/ORCA to GitHub Actions now covering PHP 7.4, 8.4, and 8.5. Callers are source-compatible. The residual risks a TPM should track are: (1) subclass exposure — if our code extends AuthorizationHeaderBuilder, RequestSigner, ResponseSigner, HmacToken, HmacAuthenticationEntryPoint, or the Malformed*Exception classes, those overrides need mirrored nullable hints or they will deprecation-fail on 8.4, and exception subclasses are especially easy to miss because happy-path tests never construct them; (2) CI coverage gaps — PHP 8.0–8.3 are not explicitly exercised in this release, so they are covered by inference rather than evidence; (3) single-vendor velocity — Acquia-maintained, community support, no SLA, no Laravel-facing documentation, 52 stars and zero dependents, so the glue is permanently ours.
Key questions (to close before committing a plan):
E_DEPRECATED promoted in any environment?Stack fit: Laravel 9/10/11 on PHP 8.1+ is a clean fit — Guzzle 7 and psr/http-message ^2.0 are satisfied out of the box, and the Symfony security-bundle and PSR bridge constraints live only in suggested/dev requirements, so they do not constrain the application. Laravel 8 on PHP 7.4 technically works but is EOL upstream, which makes it a conversation about the whole stack rather than this package. PHP 7.3 is a hard block. As TPM, the framing to use is "this rides on the stack we already have" — useful when defending the schedule estimate.
Migration path: Treat 6.2.0 as a patch-level bump from 6.1.x. Sequence the code work as: pin the constraint, then run a mechanical subclass audit (grep -r "extends \(AuthorizationHeaderBuilder\|RequestSigner\|ResponseSigner\|HmacToken\|HmacAuthenticationEntryPoint\|Malformed\)"), then add explicit ?Type to each nullable parameter in those overrides. The mechanics are trivial; the delivery risk is completeness, particularly for exception subclasses only reached on error paths. Budget a short verification task — not a story — for this, and require evidence (a deprecation-clean test run) rather than a verbal "looks fine."
Compatibility: Callers are unaffected per the release notes, so there is no API contract change to communicate externally. Two pre-existing integration hazards are worth re-testing at the same time because a runtime upgrade is the natural moment to catch them: Guzzle handler-stack ordering (the signing middleware must run after the body is finalized and before send), and deterministic body hashing for streamed or retried requests where the stream may already be consumed. Neither is new in 6.2.0, but either will surface as a mysterious 401 in production if it is latent.
Sequencing (the TPM plan of record):
Do not invert steps 5 and 6. The dependency upgrade is a gate on the runtime upgrade, not a parallel track, and collapsing them makes a signing bug and a runtime bug indistinguishable during triage.
Maintenance: Low steady-state load, which is exactly the profile a TPM wants to own. Small public API surface, infrequent releases, no framework version to chase. Plan a scheduled review at each PHP minor release rather than reserving recurring sprint capacity; the realistic cost is a day or two per PHP minor, not a standing allocation.
Support: Acquia-maintained through GitHub issues, with no Laravel-specific docs and no vendor SLA covering our glue code. Set the expectation explicitly with stakeholders: our team owns the middleware, the runbook, and first response on any signature failure. Escalation for a partner 401 stays internal until we can demonstrate the canonical string differs from theirs — which means the runbook must include how to capture and compare a canonical string.
Scaling: Effectively free on the compute axis. HMAC-SHA256 is microseconds per request and the library is stateless, so throughput tracks the HTTP client pool and nothing here becomes a bottleneck. The genuine scaling concern is operational, not technical: secret distribution and rotation across instances, regions, and environments. If the service autoscales, ensure secrets come from the same managed source the rest of the app uses rather than baked into images — otherwise scale-out silently becomes a key-drift incident.
Failure modes (build the runbook around these):
Ramp-up: Budget roughly a day for an engineer familiar with Guzzle to be productive, most of it spent on canonicalization and secret handling rather than the API itself, which is small. The knowledge that must be deliberately captured rather than learned by incident is secret rotation and failure triage — assign a named owner for each, document the canonical-string comparison procedure, and treat "who do I call when a partner returns 401" as a required line in the runbook before go-live.
How can I help you explore Laravel packages today?