Integrate a host application
Place identity, authorization storage, provider credentials, plan attempts, receipts, authenticated endpoints, and React transport around DomainKit.
This guide describes the complete application boundary around DomainKit. The host application owns the security and durability model; DomainKit owns portable connection, planning, authorization, provider, verification, and cleanup semantics.
Architecture
browser or product client
-> authenticated host endpoints
-> host identity, tenant policy, and consent checks
-> durable connection + plan-attempt + receipt storage
-> domainkit
-> Cloudflare, Vercel, or another DnsProvider
@domainkit/react uses the same boundary through Transport.Service:
@domainkit/react
-> Transport.Service
-> authenticated host client
-> the server lifecycle above
Provider credentials never cross into the browser transport.
Decide what is durable
| State | Lifetime | Host responsibility |
|---|---|---|
| OAuth or integration continuation | Short-lived and one-time | Store until callback consumption; loss may require restarting consent |
| Provider authorization | Durable | Persist account context, capabilities, credential reference, and revocation state |
| Encrypted credential | Durable and secret | Encrypt at rest, restrict access, rotate, and audit use |
| Owner binding and domain grant | Durable | Bind provider authority to your tenant and permitted domains |
| Plan attempt and authorization | Durable through apply | Correlate a server-owned plan with the digest the user reviewed |
| Apply receipt | Durable | Preserve confirmed writes and partial outcomes for later cleanup |
| Public-DNS observation | Evidence, not authority | Persist only if your product needs history, polling, or readiness state |
Do not use a browser store or evictable cache as authoritative storage for provider authorizations, plans, or receipts.
1. Define product requirements on the server
Your product decides which DNS records it needs and why. Decode those requirements at a trusted boundary:
import { DnsRecord } from "domainkit";
const requirement = DnsRecord.parse({
_tag: "TXT",
metadata: {
ownership: "product",
provenance: "domain-onboarding",
purpose: "domain-verification",
},
name: "_verify.example.com",
policy: "append",
ttl: 300,
value: "verification-value",
});
The browser may display a transport projection of these records, but it must not choose ownership, conflict policy, or provider authority.
2. Implement authorization storage
Supply one AuthorizationLifecycle.Repository for the provider authorization aggregate, encrypted
credential reference, and owner bindings. A SQL host can implement the repository as one
transaction. A host that splits database and vault storage must implement an idempotent,
recoverable saga behind the same interface.
Use domainkit/testing’s in-memory repository in tests only. It does not encrypt credentials or
provide production durability.
3. Mount provider connection routes
An interactive provider connection has two server routes:
- The start route checks the current user and tenant, creates a short-lived continuation, and returns a provider authorization URL.
- The callback route checks the same authority, consumes the continuation exactly once, exchanges the provider code, and commits the durable authorization aggregate.
A token route validates the submitted credential on the server and commits the same durable aggregate without a redirect.
After connection, reconstruct the provider client from the stored credential and non-secret provider context. Do not ask the browser to retain the provider token or account client.
4. Persist plan attempts before approval
When the user asks to review DNS changes:
- Load the authorized connection and assert its owner/domain grant.
- Reconstruct the provider.
- Create the plan against an exact zone or a discovered zone.
- Persist the complete encoded plan, digest, connection, tenant, domain, and expiry as one attempt.
- Return a browser-safe projection for review.
When the user approves, correlate the submitted digest with that server-owned attempt before calling
Provisioning.authorize. Do not rebuild a plan from browser input and treat it as the reviewed
artifact.
5. Apply once and persist the receipt
Before apply, claim or otherwise serialize the plan attempt according to your host’s request model.
Pass the persisted plan and authorization to Provisioning.apply. Store complete and partial
receipts before reporting the outcome.
An apply receipt is not merely UI progress. It is the proof needed to construct a future safe cleanup plan.
6. Map authenticated endpoints into React
Expose only application-facing operations to the browser, then adapt the client once:
import { Transport } from "domainkit";
export const transport = Transport.layerFromAsync({
connection: api.connections,
provisioning: api.provisioning,
verification: api.verification,
cleanup: api.cleanup,
});
The React transport carries a planDigest; your server can additionally correlate an opaque attempt
identifier in its authenticated session, database, or API route. The transport is a browser-safe
application contract, not a provider API.
7. Keep product readiness separate
Verification.observe reports provider and public-DNS evidence for DNS requirements. Your product
may also need provider-specific service readiness, certificate status, email verification,
polling/backoff, or a persisted onboarding phase. Keep that product lifecycle in the host instead of
flattening it into DomainKit’s observation result.
Security checklist
- Provider credentials are accepted and used only on trusted server boundaries.
- Every connection, reuse, plan, apply, cleanup, and disconnect route rechecks tenant authority.
- Domain grants are checked in addition to provider scopes.
- Interactive continuations are single-use and bound to the initiating flow.
- Plans and cleanup plans are authorized by exact digest.
- Partial receipts are stored before a retry or remediation path begins.
- Removing one domain grant does not imply deleting DNS records.
- Final-binding revocation remains retryable until the provider confirms it.