craftcms / http-message-signatures
PSR-7 compliant PHP 8.1+ implementation of HTTP Message Signatures (RFC 9421)
Package info
github.com/craftcms/http-message-signatures-php
pkg:composer/craftcms/http-message-signatures
1.x-dev
2026-05-06 11:09 UTC
Requires
- php: ^8.1
- bakame/http-structured-fields: ^2.0
- league/uri-components: ^7.0
- psr/http-factory: ^1.0
- psr/http-message: ^2.0
Requires (Dev)
- carthage-software/mago: ^1.13
- guzzlehttp/psr7: ^2.0
- http-interop/http-factory-guzzle: ^1.0
- phpstan/extension-installer: ^1.3
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.5
This package is auto-updated.
Last update: 2026-05-06 12:42:56 UTC
README
A PHP 8.4+ implementation of HTTP Message Signatures as specified in RFC 9421.
Features
- ✅ Full RFC 9421 compliance
- ✅ PSR-7 compliant - Works with any PSR-7 HTTP message implementation
- ✅ Support for multiple signature algorithms:
- HMAC-SHA256
- RSA-SHA256
- Ed25519
- ✅ Signature creation and verification
- ✅ Structured fields parsing for
signature-inputandsignatureheaders - ✅ Component derivation (headers, query parameters, request target, etc.)
- ✅ Immutable message handling (respects PSR-7 immutability)
Installation
composer require craftcms/http-message-signatures
Requirements
- PHP 8.4 or higher
- PSR-7 HTTP message implementation (e.g.,
guzzlehttp/psr7,nyholm/psr7,slim/psr7)
Dependencies
This package uses well-maintained, industry-standard libraries:
- bakame/http-structured-fields - For parsing and formatting HTTP Structured Fields (RFC 8941) used in signature headers
Usage
Creating a Signature
use HttpMessageSignatures\Signer; use HttpMessageSignatures\Algorithm\HmacSha256; use GuzzleHttp\Psr7\Request; // Create a PSR-7 request $request = new Request( 'POST', 'https://api.example.com/resource', [ 'Host' => 'api.example.com', 'Content-Type' => 'application/json', 'Date' => gmdate('D, d M Y H:i:s \G\M\T'), ], '{"data":"value"}' ); // Create signer with HMAC-SHA256 algorithm $signer = new Signer(new HmacSha256('your-secret-key')); // Sign the request (returns a new immutable PSR-7 message) $signedRequest = $signer->sign( $request, ['@method', '@path', '@authority', 'content-type', 'date'], [ 'keyid' => 'my-key-id', 'signatureId' => 'sig1', 'created' => time(), 'expires' => time() + 300, // Optional: 5 minutes ] ); // The original request is unchanged (PSR-7 immutability) // $signedRequest is a new instance with Signature and Signature-Input headers
Verifying a Signature
use HttpMessageSignatures\Verifier; use HttpMessageSignatures\Algorithm\HmacSha256; use HttpMessageSignatures\Exception\VerificationException; $verifier = new Verifier(new HmacSha256('your-secret-key')); try { // Verify the signature (returns true if valid) $isValid = $verifier->verify($signedRequest); if ($isValid) { echo "Signature is valid!\n"; } } catch (VerificationException $e) { echo "Verification failed: " . $e->getMessage() . "\n"; }
Using RSA-SHA256
use HttpMessageSignatures\Signer; use HttpMessageSignatures\Algorithm\RsaSha256; // Load your private key (for signing) $privateKey = file_get_contents('/path/to/private-key.pem'); // Optionally provide public key (for verification) $publicKey = file_get_contents('/path/to/public-key.pem'); $signer = new Signer(new RsaSha256($privateKey, $publicKey)); $signedRequest = $signer->sign( $request, ['@method', '@path', '@authority', 'content-type'], ['keyid' => 'rsa-key-1'] );
Using Ed25519
use HttpMessageSignatures\Signer; use HttpMessageSignatures\Algorithm\Ed25519; // Ed25519 requires the sodium extension $privateKey = sodium_crypto_sign_seed_keypair(...); $publicKey = sodium_crypto_sign_publickey($privateKey); $signer = new Signer(new Ed25519($privateKey, $publicKey)); $signedRequest = $signer->sign( $request, ['@method', '@path', '@authority'], ['keyid' => 'ed25519-key-1'] );
Available Components
The following components can be included in signatures:
Derived Components:
@method- HTTP method@path- Request path@query- Query string@authority- Host and port@scheme- URI scheme@target-uri- Full URI@request-target- Request target@status- Response status code (for responses)
Headers:
- Any header name (e.g.,
content-type,date,authorization)
Query Parameters:
@query-param;name="paramname"- Specific query parameter
PSR-7 Compliance
This package is fully PSR-7 compliant:
- Works with any PSR-7 implementation (
guzzlehttp/psr7,nyholm/psr7,slim/psr7, etc.) - Respects PSR-7 immutability - all methods return new message instances
- Uses only PSR-7 interfaces (
MessageInterface,RequestInterface,ResponseInterface) - No direct dependencies on specific PSR-7 implementations
Testing
composer test
Code Quality
# Run all checks (lint + PHPStan + tests) composer check # Lint code composer lint # Auto-fix lint issues composer fix # Static analysis composer phpstan
License
MIT