Agent skill

Form.io Webhooks Skill

Receive and authenticate Form.io Webhook actions. Use when setting up a Form.io webhook endpoint, verifying the HTTP Basic credentials (Authorize User / Authorize Password), debugging 401s, or handling submission create (POST), update (PUT) and delete (DELETE) requests.

Install this skill

npx skills add hookdeck/webhook-skills --skill formio-webhooks


The Form.io Webhook action calls an external URL when a form submission is created, updated or deleted. Requests are not signed. If you fill in Authorize User and Authorize Password on the action, Form.io sends them as Authorization: Basic base64(user:pass), and your endpoint authenticates the request by checking that header.

A static shared credential authenticates the sender, not the body, and gives no replay protection (no signature, no timestamp). Use HTTPS, and rotate the credential if it leaks.

When to Use This Skill

  • How do I receive Form.io webhooks?
  • How do I authenticate a Form.io Webhook action (Authorize User / Authorize Password)?
  • Does Form.io sign webhook payloads? (No: use HTTP Basic auth)
  • How do I tell a submission create from an update or delete? (By HTTP method)
  • Why does my Form.io webhook endpoint return 401 or 405?

Verification (core)

const crypto = require('crypto');

const sha = (b) => crypto.createHash('sha256').update(b).digest();
const safeEqual = (a, b) => crypto.timingSafeEqual(sha(a), sha(b));

function verifyFormioRequest(headers, user = process.env.FORMIO_WEBHOOK_USERNAME,
                             pass = process.env.FORMIO_WEBHOOK_PASSWORD) {
  if (!user || !pass) return false;                       // never accept when unconfigured
  const m = /^basic +([A-Za-z0-9+/]+={0,2}) *$/i.exec(headers.authorization || '');
  if (!m) return false;
  const decoded = Buffer.from(m[1], 'base64');
  const i = decoded.indexOf(0x3a);                        // split on the FIRST colon
  if (i < 0) return false;
  const userOk = safeEqual(decoded.subarray(0, i), Buffer.from(user));
  const passOk = safeEqual(decoded.subarray(i + 1), Buffer.from(pass));
  return userOk && passOk;                                // both evaluated, no short-circuit
}
  • Header: Authorization: Basic base64(username:password). Scheme is case-insensitive; split on the first colon because passwords may contain colons.
  • Compare username and password each in constant time, and evaluate both before deciding. In Python use hmac.compare_digest on bytes (encode both sides; str raises on non-ASCII).
  • Return 401 for a missing, malformed or mismatched header, 400 for a non-empty body that isn't a JSON object, 200 once handled.
  • Read the body raw (express.raw({ type: '*/*' })) and authenticate before parsing it.
  • Accept more than POST. The request method is set in the action. With the default Match method Form.io sends POST for creates, PUT for updates and DELETE for deletes (URL params go in the query string). The HTTP verb is the only hint of the operation: there is no event field. The examples accept POST, PUT, PATCH, GET and DELETE and handle an empty body.
  • Hookdeck: the Form.io source pre-selects POST only. Allow PUT and DELETE on the source (and any other methods your action uses), or those requests are rejected.

For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.

Operations

MethodOperation (Match)Body
POSTSubmission create{ request, response, submission, params }
PUT / PATCHSubmission update{ request, response, submission, params }
DELETESubmission deleteMay be empty; params arrive as a query string
GETOnly if chosen in the actionEmpty

Environment Variables

FORMIO_WEBHOOK_USERNAME=your-webhook-username   # "Authorize User" on the Webhook action
FORMIO_WEBHOOK_PASSWORD=your-webhook-password   # "Authorize Password" on the Webhook action

Local Development

Form.io must reach your endpoint over the network. Tunnel with the Hookdeck CLI (no account required):

npx hookdeck-cli listen 3000 formio --path /webhooks/formio

Use the printed URL as the Request URL of the Webhook action.

Resources


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 4, 2026

View on GitHub →