Agent skill
Kibana Webhooks Skill
Receive and authenticate Elastic Kibana Webhook connector requests (alerting rule actions). Use when setting up a Kibana webhook endpoint, checking HTTP Basic authentication, debugging 401s, accepting POST, PUT, PATCH, GET or DELETE, or handling a rule action's mustache-template body.
Install this skill
npx skills add hookdeck/webhook-skills --skill kibana-webhooks
The Kibana Webhook connector (alerting rule actions) sends an HTTP request to your server whenever a rule action runs. Requests are not signed: there is no signature header and no timestamp. The connector's authentication setting is none, basic, SSL or OAuth 2.0. Hookdeck's Kibana source verifies HTTP Basic auth. Custom headers and OAuth 2.0 are not covered by Hookdeck's Kibana source. This skill covers Basic auth only (not the Webhook - Case Management connector).
When to Use This Skill
- How do I receive Kibana webhooks?
- How do I verify the Kibana Webhook connector's Basic authentication?
- Does Kibana sign webhook payloads? (No: Basic auth only)
- Why does my Kibana webhook endpoint return 401?
- How do I accept PUT, PATCH, GET or DELETE from Kibana, not just POST?
- How do I handle a Kibana rule action's body template?
Hookdeck Setup
Choose Basic authentication on the Kibana Webhook connector.
Hookdeck's Kibana source pre-selects POST without managing the method, so any other method the connector uses (PUT, PATCH, GET, DELETE) must also be allowed on the source. Hookdeck never sends a 401 challenge (no WWW-Authenticate round trip), so the credentials must arrive with every request.
Verification (core)
Kibana sends Authorization: Basic base64(username:password) on every request. Split on the first colon and compare username and password each in constant time, evaluating both:
const crypto = require('crypto');
const STRICT_BASE64 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
const digest = (s) => crypto.createHash('sha256').update(s).digest();
const safeEqual = (a, b) => crypto.timingSafeEqual(digest(a), digest(b)); // equal length, never throws
function verifyBasicAuth(header, username, password) {
if (!username || !password) return false; // fail closed
const m = /^basic\s+(\S+)$/i.exec(header || ''); // scheme is case-insensitive
if (!m || !STRICT_BASE64.test(m[1])) return false; // junk after valid base64 fails
const decoded = Buffer.from(m[1], 'base64').toString('utf8');
const i = decoded.indexOf(':');
if (i === -1) return false;
const userOk = safeEqual(decoded.slice(0, i), username); // evaluate both, no short-circuit
const passOk = safeEqual(decoded.slice(i + 1), password);
return userOk && passOk;
}
Return 401 for a missing or malformed header or a mismatch, for every method. In Python use base64.b64decode(token, validate=True) and hmac.compare_digest on bytes (never str, which raises on non-ASCII). Read the body raw (express.raw({ type: '*/*' })) so any content type works, and parse it only after the check.
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.
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Methods and Body
The connector method is POST (default), PUT, PATCH, GET or DELETE (PATCH, GET and DELETE are generally available since 9.3). The examples accept all five on /webhooks/kibana, check the credential first, and handle an empty body.
There is no vendor event field. The body is the rule action's mustache template, so its shape is whatever you configure. The examples use this illustrative payload (not a vendor schema):
{"rule": "{{rule.name}}", "status": "{{alert.actionGroup}}", "context": "{{context.message}}"}
Parse JSON when it parses, otherwise keep the raw text.
Environment Variables
KIBANA_WEBHOOK_USERNAME=kibana # user name on the Webhook connector
KIBANA_WEBHOOK_PASSWORD=change-me-to-a-long-random-password
Local Development
npx hookdeck-cli listen 3000 kibana --path /webhooks/kibana
No account required. Use the printed URL as the connector URL (FastAPI: port 8000).
Resources
- references/overview.md - Connector behavior, methods, illustrative payload
- references/setup.md - Configure the Webhook connector with Basic auth and a rule action
- references/verification.md - Basic auth check in Node, Python and Next.js, gotchas
- examples/ - Runnable Express, Next.js and FastAPI handlers with tests