Agent skill
Amazon EventBridge Webhooks Skill
Receive and authenticate Amazon EventBridge API destination webhooks. Use when setting up an endpoint that EventBridge calls from a rule or pipe, checking the Basic Authorization header, debugging 401s, or handling events by source and detail-type such as EC2 Instance State-change Notification.
Install this skill
npx skills add hookdeck/webhook-skills --skill aws-eventbridge-webhooks
Amazon EventBridge delivers events to an HTTPS endpoint through an API destination: a rule or pipe target that calls your URL with a Connection's credentials. This skill covers Connections that use Basic authorization, where EventBridge populates the Authorization header. API Key and OAuth Connections are not covered.
Requests are not signed. There is no signature header and no timestamp. The only authentication is the Authorization: Basic base64(username:password) header, and your endpoint compares it with the credentials stored in the Connection.
A static shared credential authenticates the sender, not the body. It gives no replay protection (no signature, no timestamp). Serve the endpoint over HTTPS only, make handlers idempotent, and rotate the Connection credentials if they leak.
When to Use This Skill
- How do I receive Amazon EventBridge events at my own HTTP endpoint?
- How do I verify the Basic
Authorizationheader from an EventBridge API destination? - Does EventBridge sign webhook payloads? (No: use the Connection's Basic credentials)
- How do I handle
EC2 Instance State-change Notificationor my ownOrderCreatedevents? - Why does my EventBridge API destination get 401s and keep retrying?
Verification (core)
const crypto = require('crypto');
// Hash both sides: equal-length buffers, so timingSafeEqual never throws.
function safeEqual(a, b) {
const ha = crypto.createHash('sha256').update(String(a)).digest();
const hb = crypto.createHash('sha256').update(String(b)).digest();
return crypto.timingSafeEqual(ha, hb);
}
function verifyAwsEventbridgeRequest(headers, user = process.env.AWS_EVENTBRIDGE_WEBHOOK_USERNAME,
pass = process.env.AWS_EVENTBRIDGE_WEBHOOK_PASSWORD) {
if (!user || !pass) return false; // never accept when unconfigured
const m = /^basic +([A-Za-z0-9+/]+={0,2})$/i.exec((headers['authorization'] || '').trim());
if (!m) return false;
const decoded = Buffer.from(m[1], 'base64').toString('utf8');
const i = decoded.indexOf(':'); // split on the FIRST colon
if (i === -1) return false;
const userOk = safeEqual(decoded.slice(0, i), user); // evaluate both before deciding
const passOk = safeEqual(decoded.slice(i + 1), pass);
return userOk && passOk;
}
- Header:
Authorization: Basic base64(username:password). The scheme is case-insensitive. - Return
401for a missing or malformed header or a mismatch. - Accept POST, PUT, PATCH, GET and DELETE: the API destination's HTTP method is configurable (anything except CONNECT and TRACE). Handle an empty body, for example on GET.
- Read the body raw (
express.raw({ type: '*/*' })) and parse JSON only after the credential check. - Python:
hmac.compare_digeston bytes (encode both sides; passingstrraises on non-ASCII).
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Event Types
Without an input transformer the body is the event envelope (version, id, detail-type, source, account, time, region, resources, detail). Dispatch on source + detail-type:
source | detail-type | Sent When |
|---|---|---|
aws.ec2 | EC2 Instance State-change Notification | An EC2 instance changes state |
aws.s3 | Object Created | An object is created in a bucket with EventBridge notifications on |
com.example.orders | OrderCreated | Your own application puts a custom event (placeholder source) |
These are examples: the rule's event pattern decides which events reach the endpoint. With an input transformer the body is whatever the template builds, so it may not be an envelope at all.
Environment Variables
AWS_EVENTBRIDGE_WEBHOOK_USERNAME=your-connection-username # Connection > Basic > Username
AWS_EVENTBRIDGE_WEBHOOK_PASSWORD=your-connection-password # Connection > Basic > Password
Local Development
EventBridge can't reach localhost and requires a public HTTPS endpoint. Tunnel with the Hookdeck CLI (no account required):
npx hookdeck-cli listen 3000 aws-eventbridge --path /webhooks/aws-eventbridge
Use the printed URL as the API destination endpoint.
Resources
- references/overview.md - API destinations, envelope fields, request headers, retries
- references/setup.md - Create the Connection, API destination and rule
- references/verification.md - Basic auth check details, gotchas, debugging 401s
- examples/ - Runnable Express, Next.js and FastAPI handlers with tests