security domain

owns who may call a boundary, what they may read and change, and how secrets and untrusted inputs stay outside the durable core.

why

every durable write is only as trustworthy as the weakest boundary in front of it. authentication, authorization, secrets, rate limits, and webhook verification group because they are all proofs a boundary must hold before an effect is allowed: who is calling, what they may change, and whether the caller can exhaust the system. once untrusted input reaches the core, no amount of internal correctness restores the lost proof.

when to use

owns a decision when the question is what a boundary must prove before an effect is allowed — authentication, authorization, secrets, rate limits, webhook verification. accepted-input shape belongs to the contract domain.

good and bad

bad

// route handler immediately uses external data
export const handleWebhook = async (c: Context) => {
const payload = await c.req.json(); // unknown shape
const userId = payload.user_id; // no validation
const action = payload.action; // no checking
// durable write happens directly
await updateUserPlan({ userId, plan: payload.plan });
// malicious caller sends: { user_id: "admin", plan: "premium" }
// admin account is now premium without authorization
};

untrusted input reaches the durable core with no proof of sender or permission. a forged webhook sends { user_id: "admin", plan: "premium" } and the admin account silently becomes premium. signature never verified, no rate limit (quota exhausted), no audit trail of who triggered the change.

good

// boundary validates caller, signature, and rate limits BEFORE the service
export const handleWebhook = async (c: Context) => {
// 1. Prove who sent this
const authenticated = await authenticateWebhookCaller(c);
if (!authenticated) return c.json({ error: "unauthorized" }, 401);
// 2. Verify it came from the claimed provider (not spoofed)
const payload = await c.req.raw.arrayBuffer();
const signature = c.req.header("x-webhook-signature");
const verified = verifyProviderSignature(payload, signature);
if (!verified) return c.json({ error: "signature_invalid" }, 401);
// 3. Rate-limit untrusted callers
const remaining = await rateLimitBucket.tryConsume(authenticated.callerId);
if (remaining <= 0) return c.json({ error: "rate_limited" }, 429);
// 4. Validate and map external shape to domain contract
const parsed = WebhookPayloadSchema.parse(await c.req.json());
// 5. Delegate to domain service (now safe)
const result = await handleUserPlanUpdate({
callerId: authenticated.callerId,
userId: parsed.userId,
plan: parsed.plan,
});
// 6. Log the audit trail
await auditLog.record({
event: "webhook_processed",
callerId: authenticated.callerId,
userId: parsed.userId,
});
return c.json(result);
};

every proof is made explicitly at one visible boundary: authenticate, verify signature, rate-limit, schema-parse, delegate, audit. the domain service receives only trusted data and knows who triggered the change. an auditor reads one file to verify the whole posture; a new route inherits the guarantees by composing the same guard order.

search pages

go to any page