aws/aws-php-sns-message-validator
Standalone PHP library for validating incoming Amazon SNS HTTP(S) POST notifications. It checks the SigningCertURL, SignatureVersion, and Signature; requires PHP 8.1+ and OpenSSL, with no AWS SDK or Guzzle dependency.
Architecture fit: This is a deliberately narrow, framework-agnostic library: one job — cryptographically prove that an inbound HTTP POST actually came from Amazon SNS. It has no dependency on aws/aws-sdk-php or Guzzle, requires only PHP 8.1+ and ext-openssl, and exposes a small surface (Message::fromRawPostData(), Message::fromJsonString(), Message::fromPsr7Request(), MessageValidator::isValid()/validate(), InvalidSnsMessageException). For a Laravel app that receives SNS webhooks (SES bounces, S3 events, CloudWatch alarms, EventBridge-style fan-out), it slots into the HTTP kernel as a route-scoped verification layer rather than as an application framework concern. That is a good fit — it does the security-critical part and leaves orchestration to us.
Integration feasibility: High and low-cost. Composer install with no transitive conflicts, a two-call API, and injectable seams that matter for testing ($hostPattern since 1.1.0, nullable $certClient since 1.9.1) mean we can stub certificate retrieval in tests and CI without network access. Realistic effort: 1–2 engineer-days for the wrapper, middleware, tests, and runbook — the library itself is an afternoon; the surrounding hardening is the rest.
Technical risk:
SnsMessageValidator::create(). The real surface is Message + MessageValidator. Enforce review against the repo, not against blog posts.file_get_contents. That adds latency per request and makes AWS a runtime dependency of your ingest path unless a caching client is injected.MessageId idempotency. SNS delivery is at-least-once — dedupe must be built.Key questions:
SigningCertURL, and what TTL?TopicArn per route?ext-openssl compiled in (verify container images, not just local)?openssl_verify and cert fetching that this would duplicate?Stack fit: Register a dedicated route group for SNS (/webhooks/sns/{topic}) that bypasses web_csrf, session, and cookie middleware — SNS cannot present a CSRF token — and sits before authentication. A VerifySnsSignature middleware reads $request->getContent(), builds the message via Message::fromJsonString() (preferable to fromRawPostData() because Laravel may have already touched the input stream), calls validate(), and on success attaches the decoded message to the request for the controller. Dispatch a queued job from the controller and return 200 immediately; do not do business logic inline.
Migration path: Greenfield — install, write the middleware + a thin SnsValidator service wrapper (owns the cert-caching client and host pattern), add a subscription-confirmation handler, replay captured SNS fixtures in tests. Brownfield — inventory any existing manual signature checks, run the new path in shadow mode against the same fixtures, then cut over behind a feature flag and delete the old code. Keep the old path live for one release cycle.
Compatibility: Hard floor PHP 8.1+ since 1.10.0; 1.9.1 specifically fixed PHP 8.4 deprecations, so the package is being kept current for modern runtimes. No conflict with aws/aws-sdk-php — if the app already has the SDK, inject a shared, retrying HTTP client rather than letting the validator use file_get_contents. PSR-7 support (fromPsr7Request) keeps the option open if we later run on Octane/RoadRunner or move verification to an edge service.
Sequencing:
ext-openssl, and clean Composer resolution in the target image.SnsValidator wrapper: cert cache (Redis/file) + host pattern + failure taxonomy.file_get_contents, which has no per-call timeout and blocks a worker).MessageId idempotency store.Maintenance: Low. Tiny surface area, clean semver, and roughly 1–2 releases a year — almost entirely PHP-version alignment and dependency bumps. Pin to a caret constraint and let Dependabot/Renovate surface upgrades; the only recurring work is re-testing whenever we move Laravel/PHP majors. No vendored fork risk.
Support: No commercial SLA; the channel is GitHub issues plus StackOverflow with the aws-php-sdk tag. Critically, there is no Laravel-specific documentation — every framework concern (middleware, CSRF exclusion, queue integration, config) is our code. Treat the internal wrapper and runbook as the real support surface and staff accordingly.
Scaling: Signature verification is cheap (one RSA verify). The scaling constraint is the certificate fetch: uncached, every webhook pays a network round trip to AWS and inherits its availability. Cache certificates by SigningCertURL with a multi-hour TTL, warm the cache on deploy, and validate once at the edge — not again in queue workers. Budget for SNS burst fan-out: if a topic fans out to high volume, the cache is what keeps p99 flat.
Failure modes:
amazonaws.com.cn) breaks everything at once — make the pattern configurable and test it.MessageId dedupe you will double-process events.SubscriptionConfirmation never answered leaves the subscription PendingConfirmation and it expires in ~3 days — a silent "we stopped receiving events" incident. Alert on pending subscriptions.Ramp-up: Very low for a mid-level Laravel engineer — one method call and one exception type. The real learning curve is SNS semantics (confirmation handshake, at-least-once, retry-and-drop, cert rotation), not this library. Half a day to read and spike; plan the surrounding hardening (caching, dedupe, alerting) as the actual deliverable, and write the runbook at the same time as the middleware.
How can I help you explore Laravel packages today?