{"id":16619049,"url":"https://github.com/jasny/http-signature","last_synced_at":"2025-10-15T13:47:05.154Z","repository":{"id":56996778,"uuid":"171457847","full_name":"jasny/http-signature","owner":"jasny","description":"PHP library for HTTP Signature IETF draft standard RFC","archived":false,"fork":false,"pushed_at":"2020-02-14T12:56:27.000Z","size":66,"stargazers_count":9,"open_issues_count":5,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-10-11T22:33:50.458Z","etag":null,"topics":["http-signature","php","psr-15","psr-7"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jasny.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-02-19T10:58:37.000Z","updated_at":"2023-04-28T09:53:52.000Z","dependencies_parsed_at":"2022-08-21T11:10:13.433Z","dependency_job_id":null,"html_url":"https://github.com/jasny/http-signature","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/jasny/http-signature","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasny%2Fhttp-signature","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasny%2Fhttp-signature/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasny%2Fhttp-signature/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasny%2Fhttp-signature/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jasny","download_url":"https://codeload.github.com/jasny/http-signature/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jasny%2Fhttp-signature/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279084174,"owners_count":26099784,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-15T02:00:07.814Z","response_time":56,"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":["http-signature","php","psr-15","psr-7"],"created_at":"2024-10-12T02:22:36.914Z","updated_at":"2025-10-15T13:47:05.122Z","avatar_url":"https://github.com/jasny.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"HTTP Signature service and middleware (PHP)\n===\n\n[![Build Status](https://travis-ci.org/jasny/http-signature.svg?branch=master)](https://travis-ci.org/jasny/http-signature)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/jasny/http-signature/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/jasny/http-signature/?branch=master)\n[![Code Coverage](https://scrutinizer-ci.com/g/jasny/http-signature/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/jasny/http-signature/?branch=master)\n[![Packagist Stable Version](https://img.shields.io/packagist/v/jasny/http-signature.svg)](https://packagist.org/packages/jasny/http-signature)\n[![Packagist License](https://img.shields.io/packagist/l/jasny/http-signature.svg)](https://packagist.org/packages/jasny/http-signature)\n\nThis library provides a service for implementing the [IETF HTTP Signatures draft RFC](https://tools.ietf.org/html/draft-cavage-http-signatures).\nIt includes PSR-7 compatible middleware for signing requests (by an HTTP client like Guzzle) and verifying http\nsignatures.\n\nInstallation\n---\n\n    composer require jasny/http-signature\n\nUsage\n---\n\nWhen creating the `HttpSignature` service, pass a list of supported algorithms, a callback to sign request and a\ncallback to verify signatures.\n\n```php\nuse Jasny\\HttpSignature\\HttpSignature;\n\n$keys = [\n  'hmac-key-1' =\u003e 'secret',\n  'hmac-key-2' =\u003e 'god',\n];\n\n$service = new HttpSignature(\n    'hmac-sha256',\n    function (string $message, string $keyId) use ($keys): string {\n        if (!isset($keys[$keyId])) {\n            throw new OutOfBoundsException(\"Unknown sign key '$keyId'\");\n        }\n    \n        $key = $keys[$keyId];\n        return hash_hmac('sha256', $message, $key, true);\n    },\n    function (string $message, string $signature, string $keyId) use ($keys): bool {\n        if (!isset($keys[$keyId])) {\n            return false;        \n        }\n    \n        $key = $keys[$keyId];\n        $expected = hash_hmac('sha256', $message, $key, true);\n        \n        return hash_equals($expected, $signature);\n    }\n);\n```\n\n### Signing request\n\nYou can use the service to sign a PSR-7 Request.\n\n```php\n$request = new Request(); // Any PSR-7 compatible Request object\n$signedRequest = $service-\u003esign($request, $keyId);\n```\n\n### Verifying requests\n\nYou can use the service to verify the signature of a signed a PSR-7 Request.\n\n```php\n$request = new Request(); // Any PSR-7 compatible Request object\n$service-\u003everify($request);\n```\n\nIf the request is not signed, the signature is invalid, or the request doesn't meet the requirements, an\n`HttpSignatureException` is thrown. \n\n### Configuring the service\n\n#### Multiple algorithms\n\nRather than specifying a single algorithm, an array of supported algorithms may be specified in the constructor. The\nused algorithm is passed as extra parameter to the sign and verify callbacks.\n\n```php\nuse Jasny\\HttpSignature\\HttpSignature;\n\n$service = new HttpSignature(\n    ['hmac-sha256', 'rsa', 'rsa-sha256'],\n    function (string $message, string $keyId, string $algorithm): string {\n        // ...\n    },\n    function (string $message, string $signature, string $keyId, string $algorithm): bool {\n        // ...\n    }\n);\n```\n\nWhen signing, specify the algorithm;\n\n```php\n$signedRequest = $service-\u003esign($request, $keyId, 'hmac-sha256');\n```\n\nAlternatively you can get a copy of the service with one of the algorithms selected.\n\n```php\n$signService = $service-\u003ewithAlgorithm('hmac-sha256');\n$signService-\u003esign($request, $keyId);\n```\n\n#### Required headers\n\nBy default, the request target (includes the HTTP method, URL path and query parameters) and the `Date` header are\nrequired to be part of the signature message for all types of requests.\n\n```php\n$service = $service-\u003ewithRequiredHeaders('POST', ['(request-target)', 'date', 'content-type', 'digest']);\n```\n\nThe required headers can be specified per request method or as `default`.\n\nNote that the requirement only applies on including the headers to create the signature. If the headers are not used in\nthe request, they are also not part of the signature. Checking if headers are set in the request and have a valid value,\nis outside the scope of this library.\n\n#### Date header\n\nIf a `Date` header is specified, the service will check the age of the request. If it's signed to long ago an exception\nis thrown. By default a request may not be more than 300 seconds (5 minutes) old.\n\nThe time between signing a request and verifying it, may be due to latency or the system clock of client and/or server\nmight be off.\n\nThe time that is allowed can be configured as clock skew;\n\n```php\n$service = $service-\u003ewithClockSkew(1800); // Accept requests up to 30 minutes old\n```\n\n**X-Date header**\n\nBrowsers automatically set the `Date` header for AJAX requests. This makes it impossible to use this for the signature.\nAs solution, an `X-Date` header may be used that supersedes the `Date` header.\n\n### Server middleware\n\nServer middleware can be used to verify PSR-7 requests.\n\nIf the request is signed but the signature is invalid, the middleware will return a `401 Unauthorized` response and the\nhandler will not be called.\n\n#### Single pass middleware (PSR-15)\n\nThe middleware implements the PSR-15 `MiddlewareInterface`. As PSR standard many new libraries support this type of\nmiddleware, for example [Zend Stratigility](https://docs.zendframework.com/zend-stratigility/). \n\nYou're required to supply a [PSR-17 response factory](https://www.php-fig.org/psr/psr-17/#22-responsefactoryinterface),\nto create a `401 Unauthorized` response for requests with invalid signatures.\n\n```php\nuse Jasny\\HttpSignature\\HttpSignature;\nuse Jasny\\HttpSignature\\ServerMiddleware;\nuse Zend\\Stratigility\\MiddlewarePipe;\nuse Zend\\Diactoros\\ResponseFactory;\n\n$service = new HttpSignature(/* ... */);\n$responseFactory = new ResponseFactory();\n$middleware = new ServerMiddleware($service, $responseFactory);\n\n$app = new MiddlewarePipe();\n$app-\u003epipe($middleware);\n```\n\n#### Double pass middleware\n\nMy PHP libraries support double pass middleware. These are callables with the following signature;\n\n```php\nfn(ServerRequestInterface $request, ResponseInterface $response, callable $next): ResponseInterface\n```\n\nTo get a callback to be used by libraries as [Jasny Router](https://github.com/jasny/router) and\n[Relay](http://relayphp.com/), use the `asDoublePass()` method.\n\nWhen using as double pass middleware, the supplying a resource factory is optional. If not supplied, it will use the\nresponse passed when invoked.\n\n```php\nuse Jasny\\HttpSignature\\HttpSignature;\nuse Jasny\\HttpSignature\\ServerMiddleware;\nuse Relay\\RelayBuilder;\n\n$service = new HttpSignature(/* ... */);\n$middleware = new ServerMiddleware($service);\n\n$relayBuilder = new RelayBuilder($resolver);\n$relay = $relayBuilder-\u003enewInstance([\n    $middleware-\u003easDoublePass(),\n]);\n\n$response = $relay($request, $baseResponse);\n```\n\n#### Verifying requests\n\nIf a request is signed and the signature is valid, the middle with set a `signature_key_id` request attribute.\n\nFor requests that are *not* signed, the middleware does nothing. This means that you need to always check if the request\nhas the `signature_key_id`. \n\n```php\n$keyId = $request-\u003egetAttribute(`signature_key_id`);\n\nif ($keyId === null) {\n    $errorResponse = $response\n        -\u003ewithStatus(401)\n        -\u003ewithHeader('Content-Type', 'text/plain');\n        \n    $errorResponse = $service-\u003esetAuthenticateResponseHeader($errorResponse);\n    $errorResponse-\u003egetBody()-\u003ewrite('request not signed');\n}\n\n// Request is signed and signature is valid\n// ...\n```\n\n\n### Client middleware\n\nClient middleware can be used to sign requests send by PSR-7 compatible HTTP clients like\n[Guzzle](http://docs.guzzlephp.org) and [HTTPlug](http://docs.php-http.org).\n\n```php\nuse Jasny\\HttpSignature\\HttpSignature;\nuse Jasny\\HttpSignature\\ClientMiddleware;\n\n$service = new HttpSignature(/* ... */);\n$middleware = new ClientMiddleware($service, $keyId);\n```\n\nThe `$keyId` is used to the `Authorization` header and passed to the sign callback.\n\nIf the service supports multiple algorithms you need to use the `withAlgorithm` method to select one. \n\n```php\n$middleware = new ClientMiddleware($service-\u003ewithAlgorithm('hmac-sha256'));\n```\n\n#### Double pass middleware\n\nThe client middleware can be used by any client that does support double pass middleware. Such middleware are callables\nwith the following signature;\n\n```php\nfn(RequestInterface $request, ResponseInterface $response, callable $next): ResponseInterface\n```\n\nMost HTTP clients do not support double pass middleware, but a type of single pass instead. However more general\npurpose PSR-7 middleware libraries, like [Relay](http://relayphp.com/), do support double pass.\n\n```php\nuse Relay\\RelayBuilder;\n\n$relayBuilder = new RelayBuilder($resolver);\n$relay = $relayBuilder-\u003enewInstance([\n    $middleware-\u003easDoublePass(),\n]);\n\n$response = $relay($request, $baseResponse);\n```\n\n_The client middleware does not conform to PSR-15 (single pass) as that is intended for server requests only._\n\n#### Guzzle\n\n[Guzzle](http://docs.guzzlephp.org) is the most popular HTTP Client for PHP. The middleware has a `forGuzzle()` method\nthat creates a callback which can be used as Guzzle middleware.\n\nWhen using the middleware for Guzzle, it's not required to pass a `$keyId` to the constructor. Instead use Guzzle option\n`signature_key_id`. This also allows the option use different keys per request or disable signing for requests. \n\n```php\nuse GuzzleHttp\\HandlerStack;\nuse GuzzleHttp\\Client;\nuse Jasny\\HttpSignature\\HttpSignature;\nuse Jasny\\HttpSignature\\ClientMiddleware;\n\n$service = new HttpSignature(/* ... */);\n$middleware = new ClientMiddleware($service);\n\n$stack = new HandlerStack();\n$stack-\u003epush($middleware-\u003eforGuzzle());\n\n$client = new Client(['handler' =\u003e $stack, 'signature_key_id' =\u003e $keyId]);\n\n$client-\u003eget('/foo');                                    // Sign with default key\n$client-\u003eget('/foo', ['signature_key_id' =\u003e $altKeyId]); // Sign with other key\n$client-\u003eget('/foo', ['signature_key_id' =\u003e null]);      // Don't sign\n```\n\nAlternatively, you can disable signing by default and only sign when specified;\n\n```php\n$client = new Client(['handler' =\u003e $stack]);\n\n$client-\u003eget('/foo');                                 // Don't sign\n$client-\u003eget('/foo', ['signature_key_id' =\u003e $keyId]); // Sign\n```\n\n_Using an option is only available for Guzzle. For HTTPlug and other clients, you need to create a client per key or\nsign without the use of middleware._\n\n#### HTTPlug\n\n[HTTPlug](http://docs.php-http.org/en/latest/httplug/introduction.html) is the HTTP client of PHP-HTTP. It allows you\nto write reusable libraries and applications that need an HTTP client without binding to a specific implementation.\n\nThe `forHttplug()` method for the middleware creates an object that can be used as HTTPlug plugin.\n\n```php\nuse Http\\Discovery\\HttpClientDiscovery;\nuse Http\\Client\\Common\\PluginClient;\nuse Jasny\\HttpSignature\\HttpSignature;\nuse Jasny\\HttpSignature\\ClientMiddleware;\n\n$service = new HttpSignature(/* ... */);\n$middleware = new ClientMiddleware($service, $keyId);\n\n$pluginClient = new PluginClient(\n    HttpClientDiscovery::find(),\n    [\n        $middleware-\u003eforHttplug(),\n    ]\n);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjasny%2Fhttp-signature","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjasny%2Fhttp-signature","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjasny%2Fhttp-signature/lists"}