{"id":51171863,"url":"https://github.com/craftcms/http-message-signatures-php","last_synced_at":"2026-06-27T01:08:50.849Z","repository":{"id":341119518,"uuid":"1167612950","full_name":"craftcms/http-message-signatures-php","owner":"craftcms","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-18T12:59:27.000Z","size":93,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"1.x","last_synced_at":"2026-06-24T20:05:10.495Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/craftcms.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-26T13:44:44.000Z","updated_at":"2026-06-12T14:48:12.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/craftcms/http-message-signatures-php","commit_stats":null,"previous_names":["craftcms/http-message-signatures","craftcms/http-message-signatures-php"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/craftcms/http-message-signatures-php","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/craftcms%2Fhttp-message-signatures-php","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/craftcms%2Fhttp-message-signatures-php/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/craftcms%2Fhttp-message-signatures-php/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/craftcms%2Fhttp-message-signatures-php/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/craftcms","download_url":"https://codeload.github.com/craftcms/http-message-signatures-php/tar.gz/refs/heads/1.x","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/craftcms%2Fhttp-message-signatures-php/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34838071,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-26T02:00:06.560Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-27T01:08:50.270Z","updated_at":"2026-06-27T01:08:50.842Z","avatar_url":"https://github.com/craftcms.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# HTTP Message Signatures (RFC 9421)\n\nA PHP 8.1+ implementation of [HTTP Message Signatures](https://www.rfc-editor.org/rfc/rfc9421.html) as specified in RFC 9421.\n\n## Features\n\n- ✅ RFC 9421 signing and verification support\n- ✅ **PSR-7 compliant** - Works with any PSR-7 HTTP message implementation\n- ✅ Support for multiple signature algorithms:\n  - HMAC-SHA256\n  - RSA-SHA256\n  - Ed25519\n- ✅ Signature creation and verification\n- ✅ Structured fields parsing for `signature-input` and `signature` headers\n- ✅ Component derivation (headers, query parameters, request target, etc.)\n- ✅ Immutable message handling (respects PSR-7 immutability)\n\n## Installation\n\n```bash\ncomposer require craftcms/http-message-signatures\n```\n\n## Requirements\n\n- PHP 8.1 or higher\n- PSR-7 HTTP message implementation (e.g., `guzzlehttp/psr7`, `nyholm/psr7`, `slim/psr7`)\n\n## Dependencies\n\nThis package uses well-maintained, industry-standard libraries:\n\n- **[bakame/http-structured-fields](https://packagist.org/packages/bakame/http-structured-fields)** - For parsing and formatting HTTP Structured Fields (RFC 8941) used in signature headers\n\n## Usage\n\n### Creating a Signature\n\n```php\nuse HttpMessageSignatures\\Signer;\nuse HttpMessageSignatures\\Algorithm\\HmacSha256;\nuse GuzzleHttp\\Psr7\\Request;\n\n// Create a PSR-7 request\n$request = new Request(\n    'POST',\n    'https://api.example.com/resource',\n    [\n        'Host' =\u003e 'api.example.com',\n        'Content-Type' =\u003e 'application/json',\n        'Date' =\u003e gmdate('D, d M Y H:i:s \\G\\M\\T'),\n    ],\n    '{\"data\":\"value\"}'\n);\n\n// Create signer with HMAC-SHA256 algorithm\n$signer = new Signer(new HmacSha256('your-secret-key'));\n\n// Sign the request (returns a new immutable PSR-7 message)\n$signedRequest = $signer-\u003esign(\n    $request,\n    ['@method', '@path', '@authority', 'content-type', 'date'],\n    [\n        'keyid' =\u003e 'my-key-id',\n        'signatureId' =\u003e 'sig1',\n        'created' =\u003e time(),\n        'expires' =\u003e time() + 300, // Optional: 5 minutes\n    ]\n);\n\n// The original request is unchanged (PSR-7 immutability)\n// $signedRequest is a new instance with Signature and Signature-Input headers\n```\n\n### Verifying a Signature\n\n```php\nuse HttpMessageSignatures\\Verifier;\nuse HttpMessageSignatures\\Algorithm\\HmacSha256;\nuse HttpMessageSignatures\\Exception\\VerificationException;\n\n$verifier = new Verifier(new HmacSha256('your-secret-key'));\n\ntry {\n    // Verify the signature (returns true if valid)\n    $isValid = $verifier-\u003everify($signedRequest);\n    \n    if ($isValid) {\n        echo \"Signature is valid!\\n\";\n    }\n} catch (VerificationException $e) {\n    echo \"Verification failed: \" . $e-\u003egetMessage() . \"\\n\";\n}\n```\n\n### Signing URLs\n\nUse `UrlSigner` and `UrlVerifier` when the signature needs to live in the URL instead of HTTP headers.\n\nRFC 9421 does not define a signed URL format. This package provides URL signing as a convenience API that applies the same component derivation, signature base, parameters, and algorithms to a URL-carried signature.\n\n```php\nuse Http\\Factory\\Guzzle\\RequestFactory;\nuse HttpMessageSignatures\\Algorithm\\HmacSha256;\nuse HttpMessageSignatures\\Url\\UrlSigner;\nuse HttpMessageSignatures\\Url\\UrlSigningConfig;\nuse HttpMessageSignatures\\Url\\UrlVerifier;\n\n$algorithm = new HmacSha256('your-secret-key');\n$requestFactory = new RequestFactory();\n\n$config = new UrlSigningConfig(\n    components: ['@target-uri'],\n    signatureParam: 'signature',\n);\n\n$signer = new UrlSigner($algorithm, $requestFactory, $config);\n$verifier = new UrlVerifier($algorithm, $requestFactory, $config);\n\n$signedUrl = $signer-\u003esign('https://example.com/image.jpg?w=800');\n\nif ($verifier-\u003everify($signedUrl)) {\n    echo \"URL signature is valid!\\n\";\n}\n```\n\nSigned URLs only include the configured signature query parameter. The component list and signature parameters are verifier policy, so the signer and verifier must be configured with the same `UrlSigningConfig`.\n\nBy default, URL signatures cover `@target-uri`, append a `signature` query parameter, and omit `created`/`expires`. Configure `components`, `signatureParam`, `created`, `expiresAfter`, `keyid`, `nonce`, or `tag` when those values are part of your URL signing policy.\n\n```php\n$config = UrlSigningConfig::withCurrentTime(\n    components: ['@path', '@query'],\n    signatureParam: 'sig',\n    expiresAfter: 300,\n);\n```\n\nWhen signing or verifying non-GET URLs, pass a PSR-7 `RequestInterface` so the request method can be included with `@method`.\n\n### Using RSA-SHA256\n\n```php\nuse HttpMessageSignatures\\Signer;\nuse HttpMessageSignatures\\Algorithm\\RsaSha256;\n\n// Load your private key (for signing)\n$privateKey = file_get_contents('/path/to/private-key.pem');\n\n// Optionally provide public key (for verification)\n$publicKey = file_get_contents('/path/to/public-key.pem');\n\n$signer = new Signer(new RsaSha256($privateKey, $publicKey));\n\n$signedRequest = $signer-\u003esign(\n    $request,\n    ['@method', '@path', '@authority', 'content-type'],\n    ['keyid' =\u003e 'rsa-key-1']\n);\n```\n\n### Using Ed25519\n\n```php\nuse HttpMessageSignatures\\Signer;\nuse HttpMessageSignatures\\Algorithm\\Ed25519;\n\n// Ed25519 requires the sodium extension\n$privateKey = sodium_crypto_sign_seed_keypair(...);\n$publicKey = sodium_crypto_sign_publickey($privateKey);\n\n$signer = new Signer(new Ed25519($privateKey, $publicKey));\n\n$signedRequest = $signer-\u003esign(\n    $request,\n    ['@method', '@path', '@authority'],\n    ['keyid' =\u003e 'ed25519-key-1']\n);\n```\n\n### Available Components\n\nThe following components can be included in signatures:\n\n**Derived Components:**\n- `@method` - HTTP method\n- `@path` - Request path\n- `@query` - Query string\n- `@authority` - Host and port\n- `@scheme` - URI scheme\n- `@target-uri` - Full URI\n- `@request-target` - Request target\n- `@status` - Response status code (for responses)\n\n**Headers:**\n- Any header name (e.g., `content-type`, `date`, `authorization`)\n\n**Query Parameters:**\n- `@query-param;name=\"paramname\"` - Specific query parameter\n\n## PSR-7 Compliance\n\nThis package is fully PSR-7 compliant:\n\n- Works with any PSR-7 implementation (`guzzlehttp/psr7`, `nyholm/psr7`, `slim/psr7`, etc.)\n- Respects PSR-7 immutability - all methods return new message instances\n- Uses only PSR-7 interfaces (`MessageInterface`, `RequestInterface`, `ResponseInterface`)\n- No direct dependencies on specific PSR-7 implementations\n\n## Testing\n\n```bash\ncomposer test\n```\n\n## Code Quality\n\n```bash\n# Run all checks (lint + PHPStan + tests)\ncomposer check\n\n# Lint code\ncomposer lint\n\n# Auto-fix lint issues\ncomposer fix\n\n# Static analysis\ncomposer phpstan\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcraftcms%2Fhttp-message-signatures-php","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcraftcms%2Fhttp-message-signatures-php","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcraftcms%2Fhttp-message-signatures-php/lists"}