{"id":21671281,"url":"https://github.com/lachee/webhook-publisher","last_synced_at":"2026-05-17T18:36:57.450Z","repository":{"id":84936517,"uuid":"346259092","full_name":"Lachee/webhook-publisher","owner":"Lachee","description":"Publishes Webhook events behind the scenes, freeing your frontend.","archived":false,"fork":false,"pushed_at":"2023-04-26T01:13:45.000Z","size":97,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-20T07:46:13.588Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","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/Lachee.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2021-03-10T06:44:32.000Z","updated_at":"2021-04-20T04:13:46.000Z","dependencies_parsed_at":null,"dependency_job_id":"55b4b46c-a06d-4400-bd7c-954afd5a473e","html_url":"https://github.com/Lachee/webhook-publisher","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Lachee/webhook-publisher","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lachee%2Fwebhook-publisher","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lachee%2Fwebhook-publisher/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lachee%2Fwebhook-publisher/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lachee%2Fwebhook-publisher/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Lachee","download_url":"https://codeload.github.com/Lachee/webhook-publisher/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lachee%2Fwebhook-publisher/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33149933,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-17T09:28:26.183Z","status":"ssl_error","status_checked_at":"2026-05-17T09:27:52.702Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":"2024-11-25T12:40:10.838Z","updated_at":"2026-05-17T18:36:57.423Z","avatar_url":"https://github.com/Lachee.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Webhook Publisher\nPublishes Webhook events behind the scenes, freeing your frontend.\n\nThis microservice handles publishing webhook events to numerous clients without slowing down the event emitter. A fire and forget solution that requires minimal setup and no external \"subscription\" is required for your API consumers, you simply tell it what endpoints to hit.\n\n[Example Video (mp4)](https://i.lu.je/2021/IOxRsiMx01.mp4)\n\nThis is particularlly useful if you have a web service written in a language like PHP, and you wish to execute your API consumer's webhooks on a user action. You dont want to wait around for your slow consumer servers before responding to the user. \n\n# Terminology\n\n* `Publisher` is your web service that is emitting the events\n* `Hook` is the consumer of your service's webhook feature. They are the individual webhooks\n* `Publication`, `Event` these mean the same thing. They are the event you send.\n* `WHPUB`, `Service` this application\n\n# Usage\n\n## Signatures\nThe usage is fairly straight forward, but for security purposes its important you setup 2 seperate RSA keys before hand:\n\n1. Your Publisher (private) -\u003e WHPUB (public) \n2. The WHPUB (private) -\u003e Hook (public)\n\nEnsure you have the appropriate WHPUB keys configured in the .env. These are used to verify signatures and then later on, generate signatures.\n\n## Running\n\nRunning is straight forward:\n\n`node src/index.mjs`\n\n## Configuration\n\nThe configuration is likely to change as this project gets developed. Initially, there can only be one Publisher, but that is a lack of configuration infrastructure.\n\nIn the meantime, all the configuration is managed by the .env\n| Key | Description |\n|-----|-------------|\n| PORT | Port of the WHPUB Service (If using the WebService). | \n|PUBLISHER_NAME| The name of the first default publisher. Used for authorization. |\n|PUBLISHER_KEY| A path to the publisher's public key. Used to verify publications from the publisher. |\n|PRIVATE_KEY|A path to the WHPUB private key. Used to generate signatures. |\n|USER_AGENT|An optional parameter to customise the user agent that is sent in hooks. Useful for \"professionalism\". |\n\n## Publishing Events\n\nPublishing a event is straight forward. Simple use `POST /publish` to post the event payload:\n```json\n{\n    \"hooks\": [\n        \u003cwebhook-urls\u003e\n    ],\n    \"event\": \"name.of.event\",\n    \"author\": \"author-identitifcation\",\n    \"payload\": {\n      \u003csome-payload-structure\u003e\n    }\n}\n```\n\nTo authorize yourself to do this, include the following 2 headers:\n| Header | Description |\n|--------|-------------|\n| `X-Credential` | The name of the credential. As defined by the PUBLISHER_NAME |\n| `X-Signature` | A SHA256 signature of the entire JSON payload, using the private key pair of the PUBLISHER_KEY. It needs to be compatible with `crypto.verify`|\n\nYou will receive a HTTP 200 (OK) if successful, with a simple payload that looks like this:\n```json\n{\n  \"id\": \"a time sortable id\"\n}\n```\n\nYou can supply the `id` field to the `/publish` payload too if you wish to manually define the IDs. This will be required in the future for some other services such as the RedisPubSubService.\n\n## Receiving Webhooks\n\nHello! You may have been linked here because your developer didn't want to rewrite this o/\nThe webhooks are all sent out with the following headers:\n| Header | Description |\n|--------|-------------|\n| `X-Hook-ID` | Unique identifier of the webhook. This in theory should be time sortable and the publisher should have a endpoint to retrieve events after this id. |\n| `X-Hook-Time` | Unix Epoch Timestamp ( in ms) that the publication was made. This maybe different than time received as publications can be queued for long periods. |\n| `X-Hook-Author` | Copy of the `author` field in the payload. It's the user that trigged the webhook. |\n| `X-Hook-Event` | Copy of the `event` field in the payload. It's the event that triggered the webhook. |\n| `X-Hook-Signature` | A SHA356 Signature of the entire body. Ensure this is valid with the public key pair of the PRIVATE_KEY. Ask your API host to provide the public key. |\n\nThe payload looks like so:\n```json\n{\n  \"id\": \"60489484065f8584a4c2b076000025\",\n  \"event\": \"name.of.event\",\n  \"author\": \"unique-identifier\",\n  \"payload\": {\n    \u003cevent-payload\u003e\n  }\n}\n```\n\n### Security\nIt's important that, as a consumer of the webhook, you verify that the signature has come from this service. Use the Public Key and verify the `X-Hook-Signature` of the body before continue processing webhooks.\n\nThe verify function must be equivilent of [Node.JS crypto.Sign](https://nodejs.org/api/crypto.html#crypto_class_sign). It uses a `SHA256` algorithm. \n\n# Docker\n\n### Build\n`docker build -t lachee/webhook-publisher`\n\n### Run\nSee the sample `docker-run.sh` file. But basically:\n```sh\ndocker run \\\n    -p 7080:7080 \\\n    --env-file \"$(pwd)\"/.env \\\n    --mount type=bind,source=\"$(pwd)\"/.keys,target=/usr/src/app/.keys,readonly \\\n    -d lachee/webhook-publisher\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flachee%2Fwebhook-publisher","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flachee%2Fwebhook-publisher","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flachee%2Fwebhook-publisher/lists"}