Skip to content

craftcms/http-message-signatures

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

HTTP Message Signatures (RFC 9421)

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-input and signature headers
  • âś… Component derivation (headers, query parameters, request target, etc.)
  • âś… Immutable message handling (respects PSR-7 immutability)

Installation

composer require timkelty/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:

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

Laravel Integration

This package includes first-class Laravel support:

Installation

composer require timkelty/http-message-signatures

Configuration

Publish the configuration file:

php artisan vendor:publish --tag=http-message-signatures-config

Configure your keys in .env:

HTTP_SIGNATURE_ALGORITHM=hmac-sha256
HTTP_SIGNATURE_HMAC_SECRET_KEY=your-secret-key
HTTP_SIGNATURE_KEY_ID=my-key-id

Usage

Using Facades

use HttpMessageSignatures\Laravel\Facades\HttpMessageSigner;
use HttpMessageSignatures\Laravel\Facades\HttpMessageVerifier;

// Sign a request
$signedRequest = HttpMessageSigner::sign($request, [
    '@method', '@path', '@authority', 'content-type'
], ['keyid' => 'my-key']);

// Verify a request
$isValid = HttpMessageVerifier::verify($request);

Using Helper Functions

use function HttpMessageSignatures\Laravel\sign_request;
use function HttpMessageSignatures\Laravel\sign_http_message;
use function HttpMessageSignatures\Laravel\verify_http_message;

// Sign a Laravel Request
$signedRequest = sign_request($request);

// Sign any HTTP message
$signedMessage = sign_http_message($message);

// Verify an HTTP message
$isValid = verify_http_message($message);

Using Dependency Injection

use HttpMessageSignatures\Signer;
use HttpMessageSignatures\Verifier;

class MyController
{
    public function __construct(
        private Signer $signer,
        private Verifier $verifier
    ) {}

    public function sign(Request $request)
    {
        $signed = $this->signer->sign($request, [
            '@method', '@path', '@authority'
        ], ['keyid' => 'my-key']);

        return response()->json(['signed' => true]);
    }
}

Service Provider

The package automatically registers a service provider. All classes are bound in the container and can be injected via dependency injection.

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

Development

Running Tests

composer test
# or
./vendor/bin/pest

Code Style

This project uses Laravel Pint for code style formatting:

composer pint
# or
./vendor/bin/pint

Static Analysis

This project uses PHPStan for static analysis:

composer phpstan
# or
./vendor/bin/phpstan analyse

License

MIT

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages