Agent skill
Forgejo Webhooks Skill
Receive and verify Forgejo webhooks. Use when setting up Forgejo or Codeberg webhook handlers, debugging X-Forgejo-Signature verification, or handling self-hosted Git events like push, pull_request, issues, issue_comment, create, delete, or release.
Install this skill
npx skills add hookdeck/webhook-skills --skill forgejo-webhooks
When to Use This Skill
- How do I receive Forgejo (or Codeberg) webhooks?
- How do I verify the
X-Forgejo-Signatureheader? - Why is my Forgejo webhook signature verification failing?
- How do I handle
push,pull_request,issues,issue_comment,create,deleteorreleaseevents from Forgejo? - Which header carries the Forgejo event name (
X-Forgejo-Event-TypevsX-Forgejo-Event)?
Setup note
Set a secret on the Forgejo webhook. Without one, deliveries are unsigned and fail verification. Set the webhook's HTTP method to POST and its content type to application/json. Form-encoded and GET deliveries sign the JSON payload rather than the request body and fail verification.
Verification (core)
Forgejo signs the raw request body bytes with HMAC-SHA256 keyed on the webhook Secret (used as UTF-8 bytes, not decoded). X-Forgejo-Signature is the bare lowercase hex digest: no sha256= prefix, no timestamp, nothing else signed. Compare the whole header value as one digest. If no secret is set, the header is still sent but empty, so reject an empty value.
Node:
const crypto = require('crypto');
function verify(rawBody, signature, secret) { // rawBody: Buffer
if (!secret || typeof signature !== 'string' || !/^[0-9a-fA-F]{64}$/.test(signature)) return false;
const expected = crypto.createHmac('sha256', Buffer.from(secret, 'utf8')).update(rawBody).digest();
return crypto.timingSafeEqual(Buffer.from(signature.toLowerCase(), 'hex'), expected);
}
Python:
import hashlib, hmac, re
def verify(raw_body: bytes, signature: str | None, secret: str | None) -> bool:
if not secret or not signature or not re.fullmatch(r"[0-9a-fA-F]{64}", signature):
return False
expected = hmac.new(secret.encode("utf-8"), raw_body, hashlib.sha256).digest()
return hmac.compare_digest(bytes.fromhex(signature), expected)
Return 401 for a missing, empty, malformed or mismatched signature. There is no signed timestamp, so there is no replay window to check; use X-Forgejo-Delivery for idempotency. Read the raw bytes for any content type (in Express: express.raw({ type: '*/*' })) and parse only after verifying.
For complete handlers with route wiring, event dispatch, and tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Common Event Types
Dispatch on the X-Forgejo-Event-Type header (the exact event type, e.g. issue_assign). X-Forgejo-Event is the coarser group (e.g. issues) and is empty for package, schedule and workflow_dispatch events.
| Event type | Description |
|---|---|
push | Commits pushed to a branch or tag |
pull_request | Pull request opened, closed, reopened, edited |
issues | Issue opened, closed, reopened, edited |
issue_comment | Comment on an issue |
pull_request_comment | Comment on a pull request (sent with X-Forgejo-Event: issue_) |
create | Branch or tag created |
delete | Branch or tag deleted |
release | Release published, updated, deleted |
Forgejo documents 41 event types in all, including fork, issue_assign, issue_label, issue_milestone, pull_request_assign, pull_request_label and pull_request_milestone. The examples handle the common ones above and log the rest. Most bodies also carry an action.
Full reference: Forgejo webhooks
Important Headers
| Header | Description |
|---|---|
X-Forgejo-Signature | Bare hex HMAC-SHA256 of the raw body (empty if no secret) |
X-Forgejo-Event-Type | Exact event type (push, issue_assign, ...) |
X-Forgejo-Event | Coarser event group (push, issues, ...) |
X-Forgejo-Delivery | Unique delivery UUID |
X-Hub-Signature-256 | Same digest as sha256=<hex> (also sent as X-Gitea-Signature, X-Gogs-Signature) |
Environment Variables
FORGEJO_WEBHOOK_SECRET=your_webhook_secret # The "Secret" field of the Forgejo webhook
Local Development
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 forgejo --path /webhooks/forgejo
Reference Materials
- references/overview.md - Forgejo webhook concepts and events
- references/setup.md - Configuration guide
- references/verification.md - Signature verification details