gremo/hmac-authentication-bundle
A Symfony bundle for HMAC request authentication. It signs and verifies API requests using shared secrets, timestamps, and nonces, integrating with Symfony Security to protect stateless REST endpoints from tampering and replay attacks.
This is a Symfony bundle, not a Laravel package — that single fact drives the whole assessment. There is no service provider, no config/hmac.php, and the package pulls in symfony/security-* and symfony/http-kernel, so composer require gremo/hmac-authentication-bundle inside a Laravel app adds dead weight and nothing else. For a Laravel codebase, treat it as a reference implementation for HMAC request signing, and as a real dependency only if you also maintain a Symfony service.
Where to look first, in this order:
DependencyInjection/Configuration.php — the authoritative list of config keys (algorithm, key pair, timestamp window if present) and their defaults. Do not trust blog snippets; the README and this file are the contract.Authorization header format (typically HMAC <public_key>:<signature>).First use case, either way: protecting a private REST endpoint used for service-to-service calls (webhooks, internal API, cron callbacks). On the Symfony side you register the bundle, set the key pair, attach it to a firewall, and verify with curl plus a tiny signing script. On the Laravel side the equivalent first step is a HmacAuthenticate middleware that reproduces the same canonical string — start there before touching any client code.
Pattern A — Symfony service in the same estate. Register the bundle in bundles.php, configure private_key/public_key/algorithm under the bundle's config key, wire it into the firewall, and let the bundle's listener reject unsigned requests. Your Laravel app is then just the client: a Guzzle middleware (or Http::withHeaders) that computes the signature on the way out.
Pattern B — Port the scheme into Laravel middleware (the realistic path). Lift the string-to-sign and header format from the bundle, then:
$canonical = implode("\n", [$method, $path, $timestamp, hash('sha256', $body)]);
$signature = base64_encode(hash_hmac('sha256', $canonical, $secret, true));
if (! hash_equals($expected, $provided)) abort(401);
Register it as route middleware on /api/internal/*, resolve the secret from a per-client key store, and enforce a timestamp window (abs(now() - $timestamp) <= 300) to blunt replay.
Pattern C — Shared signing library. If more than one Laravel service calls the protected endpoint, extract the signer into a small private package (HmacSigner::sign(Request)), and unit-test it against a captured fixture from the Symfony verifier. That fixture is the only reliable way to prove both sides agree.
Key management. One key pair per client, stored in config/services.php sourced from env, not a single global secret. Design for rotation now: accept key_id in the header and look it up, so you can roll a secret without a coordinated deploy.
hash_equals, never ===; timing side channels are real on signature checks.public_key to a user/entity), the signing algorithm setting, and the security listener itself (decorate it to add nonce checks the bundle may not ship).How can I help you explore Laravel packages today?