{"id":18514189,"url":"https://github.com/tizz98/webhook-utils","last_synced_at":"2025-05-14T13:11:04.910Z","repository":{"id":38823597,"uuid":"442874661","full_name":"tizz98/webhook-utils","owner":"tizz98","description":"Webhook utilities","archived":false,"fork":false,"pushed_at":"2022-12-08T13:17:46.000Z","size":148,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-22T04:09:00.053Z","etag":null,"topics":["python-webhook","python3","webhooks"],"latest_commit_sha":null,"homepage":"","language":"Python","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/tizz98.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2021-12-29T19:47:01.000Z","updated_at":"2024-06-05T15:33:40.000Z","dependencies_parsed_at":"2023-01-25T04:45:16.214Z","dependency_job_id":null,"html_url":"https://github.com/tizz98/webhook-utils","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tizz98%2Fwebhook-utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tizz98%2Fwebhook-utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tizz98%2Fwebhook-utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tizz98%2Fwebhook-utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tizz98","download_url":"https://codeload.github.com/tizz98/webhook-utils/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254149987,"owners_count":22022853,"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","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":["python-webhook","python3","webhooks"],"created_at":"2024-11-06T15:42:20.431Z","updated_at":"2025-05-14T13:11:04.845Z","avatar_url":"https://github.com/tizz98.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Webhook Utils\n\nA set of utilities for interacting with [webhooks](https://webhooks.dev).\n\n[![Test Webhook Utils](https://github.com/tizz98/webhook-utils/actions/workflows/main.yaml/badge.svg?branch=main)](https://github.com/tizz98/webhook-utils/actions/workflows/main.yaml)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue)](https://github.com/tizz98/py-paas/tree/main/LICENSE)\n[![codecov](https://codecov.io/gh/tizz98/webhook-utils/branch/main/graph/badge.svg?token=HYT07K0ZHQ)](https://codecov.io/gh/tizz98/webhook-utils)\n[![PyPI pyversions](https://img.shields.io/pypi/pyversions/webhook-utils.svg)](https://pypi.python.org/pypi/webhook-utils/)\n\n[Installation](#installation) | [Usage](#usage) | [HTTPX](#httpx) | [FastAPI](#fastapi) | [Contributing](CONTRIBUTING.md) | [End-to-End Examples](./examples/README.md)\n\n## Installation\n\n```shell\npip install webhook-utils\n```\n\n## Usage\n\n### Crypto\n\nAvailable hash algorithms for all methods are:\n- `md5` (not recommended)\n- `sha1`\n- `sha256` (recommended)\n\nLearn more about HMAC signatures [here](https://webhooks.dev/docs/auth/#hmac).\n\n#### Generating HMAC signatures\n\nBare usage:\n```python\nfrom webhook_utils.crypto import generate_sha256_signature\n\nprint(generate_sha256_signature(b'secret-key', b'some-message'))\n```\n\n#### Comparing HMAC signatures\n\nBare usage:\n```python\nfrom webhook_utils.crypto import compare_sha256_signature\n\nis_valid_signature = compare_sha256_signature(\n    b'secret-key',\n    b'some-message',\n    'expected-signature',\n)\nif not is_valid_signature:\n    raise ValueError('Invalid signature')\n```\n\n### Httpx\n\n`webhook-utils` has a built-in `httpx.Auth` class that can be used to\nautomatically sign requests made with an `httpx.Client`.\n\nAn `X-Webhook-Signature` header will be added to all `POST` requests.\nThe signature will be generated using the `webhook_key` and the\nprovided signature method (defaults to `sha256`).\n\nThe header, signature, and http methods can be customized by passing\nthe `header_name`, `gen_signature_method`, and `methods` keyword arguments.\n\n```shell\npip install webhook-utils[httpx]\n```\n\n```python\nimport httpx\nfrom webhook_utils.contrib.httpx_auth import WebhookAuth\nfrom webhook_utils.crypto import generate_sha1_signature\n\n# Basic usage\nauth = WebhookAuth(\"secret-key\")\nclient = httpx.Client(auth=auth)\n\n\n# Customized usage\nauth = WebhookAuth(\n    \"secret-key\",\n    header_name=\"My-Webhook-Signature\",\n    gen_signature_method=generate_sha1_signature,\n    methods={\"POST\", \"PUT\"},\n)\nclient = httpx.Client(auth=auth)\nclient.post(\"https://example.com/webhook\", json={\"foo\": \"bar\"})\n```\n\n### FastAPI\n\n`webhook-utils` has a built-in `WebhookRouter` class that can be used to\nwrap a `fastapi.APIRouter` to automatically verify incoming request signatures.\n\n```shell\npip install webhook-utils[fastapi]\n```\n\n```python\nfrom fastapi import FastAPI, APIRouter\nfrom webhook_utils.contrib.fastapi import WebhookRouter\n\napp = FastAPI()\nwebhook_router = WebhookRouter(\n    APIRouter(prefix=\"/webhooks\"),\n    webhook_key=\"secret\",\n)\n\n\n@webhook_router.on(\"/demo-webhook\")\ndef demo_event_handler():\n    return {\"status\": \"ok\"}\n\n\napp.include_router(webhook_router.api_router)\n```\n\n## Publishing to PYPI\n\n```shell\npoetry build\n# Verify that everything looks correct on test.pypi.org\npoetry publish -r testpypi\npoetry publish\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftizz98%2Fwebhook-utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftizz98%2Fwebhook-utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftizz98%2Fwebhook-utils/lists"}