Skip to main content

Acumatica Webhook Authenticator

  • August 17, 2026
  • 2 replies
  • 48 views

Forum|alt.badge.img+9

If you've built an inbound webhook with PX.Api.Webhooks.IWebhookHandler, you've hit the same wall we (Claude and I) did: the platform hands you the request and leaves authentication entirely to you. The official sample compares a bearer token with != — no HMAC, no timing safety, no replay protection, and a secret hardcoded next to it. Every team ends up re-implementing signature verification, and most of the common mistakes (verifying re-encoded text instead of raw bytes, short-circuiting comparisons, distinguishable error responses) are invisible until someone exploits them.

So we built it once, properly, and we're open-sourcing it under MIT:

https://github.com/AISI-Dev-Co/AISI.AcumaticaWebhookAuthenticator

A complete, authenticated GitHub webhook is this:

public class PushEventHandler : AuthenticatedWebhookHandlerBase{    protected override IWebhookAuthenticator CreateAuthenticator(IWebhookSecretProvider secrets) =>        new HmacAuthenticator(WebhookAuthPresets.GitHub(secrets));    protected override Task ProcessAsync(AuthenticatedWebhookContext context, CancellationToken cancellation)    {        // context.Body is the exact byte buffer the signature verified.    }}

The secret doesn't live in your code — an administrator maintains it on a Webhook Secrets screen (AS301000) that ships in the customization package, stored via [PXRSACryptString] per webhook registration. Edits go live within 30 seconds, no republish, and it works on SaaS.

What's in the box:

  • Five schemes — HMAC, HMAC with a replay window, shared secret, HTTP Basic, and an explicit "none" (so no-auth is a written-down decision, not a forgotten gap). Presets for GitHub, Shopify and Stripe, and a signed-payload template language ({timestamp}.{body}, {header:Name}, …) for everything else — Stripe's compound t=/v1= header and per-value timestamps included.
  • Zero-downtime secret rotation — old and new secrets both accepted until the overlap you set expires. No dropped requests mid-rotation, no maintenance window.
  • Per-webhook IP allowlists (IPv4/IPv6 CIDR), admin-configurable on the same screen — for deployments behind a trusted proxy, as defence in depth on top of a signature.
  • A signature debuggerWebhookSignatureTester shows the exact string your configuration signed, the signatures it expected, and what the sender actually sent. It ends the hour every webhook integration starts with.
  • Security throughout — raw-bytes verification, constant-time comparison, fail-closed on missing secrets, and uniform 401s (diagnostic codes go to PXTrace only, never to the caller).

Getting started is four steps: import and publish AISI.WebhookAuthenticator.zip from the release (it creates the table, screen and access rights — no manual SQL), write a handler like the one above, register it on the Webhooks screen (SM304000), and enter the secret on AS301000.

Where we've used the patterns: Shopify orders → Sales Orders, Stripe payment events → AR, 3PL tracking callbacks, DocuSign envelope completion, and iPaaS tools (Boomi/Celigo/Zapier) that only offer a static header — which is exactly what the shared-secret scheme plus an IP allowlist is for.

Supports Acumatica 2025 R2 – 2026 R1. Issues, PRs and "sender X does something weird" reports very welcome — new schemes just need a known-good and known-bad vector.

 

Happy Auth’ing!

2 replies

Kyle Vanderstoep
Varsity I
Forum|alt.badge.img+2

This is awesome, fantastic identification of a need.


Chris Hackett
Community Manager
Forum|alt.badge.img
  • Acumatica Community Manager
  • August 18, 2026

Thank you for sharing this with the community ​@aiwan!