Webhook Verification

Fail-closed HMAC signature verification for inbound bot webhooks

python
from praisonaiagents import Agent

agent = Agent(name="webhook-agent", instructions="Verify and process incoming webhooks.")
agent.start("Verify the HMAC signature on this incoming webhook from GitHub.")

Inbound webhooks are verified by default — misconfigured secrets return HTTP 401 instead of silently accepting unsigned traffic.

bash
export LINEAR_WEBHOOK_SECRET=your-linear-signing-secret
export LINEAR_OAUTH_TOKEN=your-linear-token
praisonai bot linear --token "$LINEAR_OAUTH_TOKEN"

The user posts a webhook; HMAC verification runs before the agent handles the payload.

Diagram

verified

rejected

Inbound Webhook

enforce_webhook_verification

Agent run

HTTP 401

Quick Start

  1. Set your signing secret
    bash
    export LINEAR_WEBHOOK_SECRET=your-linear-secret
    # or for AgentMail:
    export AGENTMAIL_WEBHOOK_SECRET=your-agentmail-secret
  2. Run the bot — verification is on by default
    bash
    praisonai bot linear --token $LINEAR_OAUTH_TOKEN
  3. Local dev without a real platform
    bash
    PRAISONAI_INSECURE_WEBHOOKS=true praisonai bot linear --token $LINEAR_OAUTH_TOKEN

Which mode am I in?

Diagram

Yes

No

true

unset/false

Secret set?

Fail-closed verification — production

PRAISONAI_INSECURE_WEBHOOKS?

Skip verification — dev only, logs warning

Reject all webhooks — HTTP 401

How It Works

Diagram
AgentHmacWebhookVerifierenforce_webhook_verificationBotPlatformAgentHmacWebhookVerifierenforce_webhook_verificationBotPlatformalt[verified][rejected]POST webhookheaders + raw bodyverify()truedispatchfalseHTTP 401
accepts_webhooksVerifier configuredPRAISONAI_INSECURE_WEBHOOKSOutcome
false——No verification gate
trueyesunsetVerify; 401 on failure
truenounset401 (fail-closed)
true—trueSkip with warning

Configuration Options

VariablePurpose
PRAISONAI_INSECURE_WEBHOOKSSet to true / 1 / yes to disable verification globally (local dev only)
LINEAR_WEBHOOK_SECRETHMAC secret for Linear webhooks
AGENTMAIL_WEBHOOK_SECRETHMAC secret for AgentMail webhooks (required in production; API token is not a fallback)
WHATSAPP_APP_SECRETMeta app secret for Cloud-mode WhatsApp webhooks
PlatformCapabilities fieldDefaultMeaning
accepts_webhooksFalseChannel receives inbound HTTP webhooks
verifies_webhook_signatureFalseAdapter exposes a verifier implementation

Common Patterns

Built-in adapter, secret only — set the platform env var and run the bot; no code required.

Custom adapter with HmacWebhookVerifier:

python
from praisonai.bots.webhook_security import HmacWebhookVerifier

verifier = HmacWebhookVerifier(
    secret="your-secret",
    signature_headers=["X-Hub-Signature-256"],
    prefix="sha256=",
)

Custom ingress with the shared gate:

python
from praisonai.bots.webhook_security import enforce_webhook_verification

ok = enforce_webhook_verification(
    accepts_webhooks=True,
    verifier=verifier,
    headers=dict(request.headers),
    raw_body=await request.body(),
    platform="mychat",
)
if not ok:
    return Response(status_code=401)

Best Practices

Never set PRAISONAI_INSECURE_WEBHOOKS in production

The override logs a warning on every request and disables all signature checks.

Use the shared helper instead of rolling your own HMAC

verify_hmac and HmacWebhookVerifier fail closed on missing secrets, unknown digest algorithms, and verifier exceptions.

Rotate signing secrets with the platform

Update both the platform webhook config and your env var at the same time.

Related