ADR-052: Connected Apps and Signed Hooks
Tier-2 integrations use plugin-bound credentials and replay-resistant, fail-closed synchronous hooks.
- Status: Accepted
- Date: 2026-07-18
Context
Some integrations must deploy independently of Owlat and cannot run inside Convex or the Nuxt bundle. Their network responses, credentials, and endpoints are untrusted and need a smaller boundary than arbitrary callbacks.
Decision
A connected app is bound to one bundled plugin, explicit capabilities, and plugin-scoped API keys. Shared hook secrets are generated with a CSPRNG, sealed with AES-256-GCM under an HKDF-derived key, revealed once, and never returned by a query.
Synchronous draft, gate, and score hooks use domain-separated HMAC-SHA256 signatures over the exact body and request metadata. Nonces prevent replay; verification is constant-time. Endpoint validation and guarded fetches defend against private targets, DNS rebinding, and unsafe redirects. Disable or revoke is checked before every operation, and revocation cascades to plugin-bound API keys.
Consequences
Connected apps can extend Owlat without receiving a Convex context or deployment secrets. Network uncertainty fails in the safe direction, delivery logs are tenant-scoped and redacted, and restrict-only gate responses cannot approve a send. See Connected Apps.