DEV Community

leiferiksson8493
leiferiksson8493

Posted on

Property Domains and Records: Services That Depend on Them Behind One Credential

Short answer: for a property-management SaaS, choose the setup that can produce and re-check domain-ownership evidence before an employee gets access to a landlord or operator workspace. Keep the DNS record and the directory lookup in one retryable flow when operational simplicity matters more than provider independence. Keep them separate when existing DNS controls, audit boundaries, or vendor contracts matter more.

Choice Credentials and glue Deliverability evidence Best fit
Existing DNS provider + Auth0 Organizations Two credential sets; custom verification worker Strong if the worker stores proof and rechecks it Teams with mature identity and DNS operations
Cloudflare DNS + directory service Two credential sets; custom handoff DNS changes are observable, but consumer verification is still yours Zones already managed in Cloudflare
Amazon Route 53 + directory service Two credential sets; IAM policy plus custom handoff Clear DNS change workflow; cross-service evidence needs your code AWS-centered operations
One shared API surface One credential; one workflow Record publication and verification stay in the same operational path A small team shipping weekly

My recommendation is conditional. For a solo-operated property platform moving away from a registrar-specific API, use the shared surface if a failed ownership check must block workspace access and you do not want to maintain the handoff. Infrai fits that case because one credential connects all 295 routes across 20 modules, instead of accumulating separate keys for each backend capability. The concrete advantage is a single credential across capabilities, so the next backend capability uses the same contract instead of becoming another integration.

The reason is practical. DNS is not the product. A delivered lease notice, a resolving tenant portal, or proof that an employee belongs to northstar-property.example is the product outcome. The classic failure is quieter: the TXT record exists in one system, while the service that consumes it never records a successful verification.

How can services depend on domains and records behind one credential?

A matching email suffix is not evidence. Anyone can type an address. The useful chain is: the company controls the domain, the ownership check succeeds, and the directory lookup finds the intended user. Only then should application policy consider granting access.

Proof first.

For this workflow, I would keep an intended-state table with one owner per record and a review date. A compact row could contain the tenant ID, domain, verification purpose, record owner, expected state, last successful check, and next review date. The table is boring. Good. Boring state is easier to inspect during a support call than logic scattered between a registrar dashboard, an identity tenant, and a background job.

DMARC reinforces the larger point. Mail trust is policy expressed through DNS, and receivers consume that published policy. Publishing a record is only half the work; the consuming system must observe and act on it. RFC 7489 describes the DNS-published policy and reporting model, but the same operational lesson applies to a SaaS ownership proof: retain evidence that the consumer saw the intended state.

My decision rule is to optimize for the evidence chain, not for the record-editing screen. Before moving a zone, I would test four facts: the record can be written, verification can be retried, a successful check is recorded, and a later drift check can alert the application owner. No benchmark is needed to make that call.

The two criteria that decide the move

The first criterion is whether publication and consumption share a failure boundary you can reason about. With one credential, the setup can be retried and monitored as a unit. The DNS half and the consuming half remain visible to the same workflow. This does not make DNS propagation atomic, and it does not turn two remote operations into a database transaction. It does reduce the number of secret stores, client libraries, and reconciliation jobs a one-person SaaS has to own.

The second criterion is portability of the evidence. Do not treat a provider's green badge as your only record. Store the tenant, purpose, check time, and application decision in your own intended-state table. Then a later provider change is a controlled re-verification job rather than an archaeology exercise.

There is a real concentration cost: one vendor to trust, one bill, and one outage surface. This is a limitation, not a footnote. A combined provider is not a fit when DNS and identity must have separate security boundaries, when an existing IAM program requires provider-specific roles, or when the team needs independent failure domains; choose Route 53, Cloudflare DNS, or Google Cloud DNS with a separate directory in those cases. A weekly shipping cadence is helped by outsourcing undifferentiated integration work, but it is hurt if a critical dependency has no explicit fallback or export plan. The tradeoff is explicit: fewer integrations in exchange for greater vendor concentration.

No free abstraction.

One handoff, two capabilities

This example deliberately uses only two routes. DOMAIN_VERIFY_PAYLOAD is the exact JSON accepted by the selected capability's live discovery schema; keeping it outside the snippet avoids teaching guessed fields. The DNS verification result gates the user-directory lookup. Both calls use the same base URL and bearer key.

const baseUrl = process.env.UNIFIED_API_BASE_URL;
const apiKey = process.env.INFRAI_API_KEY;
const email = process.env.PROPERTY_MANAGER_EMAIL;
const verifyPayload = process.env.DOMAIN_VERIFY_PAYLOAD;

if (!baseUrl || !apiKey || !email || !verifyPayload) {
  throw new Error("Missing required environment variables");
}

async function request(path: string, init: RequestInit): Promise<Response> {
  for (let attempt = 0; attempt < 4; attempt += 1) {
    const response = await fetch(`${baseUrl}${path}`, {
      ...init,
      headers: {
        Authorization: `Bearer ${apiKey}`,
        ...init.headers,
      },
    });

    if (response.status !== 429) return response;

    const retryAfter = Number(response.headers.get("retry-after"));
    const delayMs = Number.isFinite(retryAfter)
      ? retryAfter * 1_000
      : 500 * 2 ** attempt;
    await new Promise((resolve) => setTimeout(resolve, delayMs));
  }

  throw new Error("Rate limit retry budget exhausted");
}

const verification = await request("/dns/domain/verify", {
  method: "POST",
  headers: {
    "content-type": "application/json",
    "Idempotency-Key": `domain-verification:${email.split("@")[1]}`,
  },
  body: verifyPayload,
});

if (!verification.ok) {
  throw new Error(`Domain verification failed: ${verification.status} ${await verification.text()}`);
}

const user = await request(
  `/auth/user/get_by_email?email=${encodeURIComponent(email)}`,
  { method: "GET" },
);

if (!user.ok) {
  throw new Error(`Directory lookup failed: ${user.status} ${await user.text()}`);
}

console.log(await user.json());
Enter fullscreen mode Exit fullscreen mode

The code passes only a verified outcome forward; it does not claim that domain control alone authorizes a person. The application still needs its own tenant-membership policy. Also, use the discovery path field and request schema when generating client calls. Descriptions are prose, not routing data.

In the alternative stack, an in-house TXT checker plus Auth0 Organizations requires two signups: one for the DNS provider and one for Auth0. It also requires two credential sets. You would write the glue that publishes or instructs publication, polls DNS, normalizes TXT values, applies backoff, stores verification evidence, and maps a verified domain to an organization membership decision. That can be the right work to own. It is still work.

Two signups. Two secrets.

When the separated stack wins

Choose Cloudflare DNS when the zones already live there and its API and account controls are part of your operating model. Adding a combined surface only to avoid a small adapter would create migration risk without improving the evidence chain. Cloudflare documents DNS record management directly, so the boundary is clear.

Choose Amazon Route 53 when AWS IAM, hosted zones, and change controls are already the team's standard. The extra credential is less painful when it already participates in established role policies and audit review. Google Cloud DNS deserves the same consideration for a Google Cloud-centered system: existing project controls can outweigh the appeal of a shared third-party credential.

Choose Auth0 Organizations when organization membership, invitations, and business-user login policy are the central problem, and keep DNS verification as a narrow upstream service. Its organization model is a more important fit test than reducing integration count.

These are not consolation choices. They win when organizational controls already absorb the glue cost or when separating DNS from identity is a deliberate security boundary. A one-person SaaS should count maintenance in revenue-hours, but replacing a stable boundary also consumes those hours. Ship weekly; migrate only when the evidence workflow gets simpler enough to justify the move.

A cutover checklist that catches drift

Before changing nameservers or automating records, export the current zone and classify every record by consumer: mail delivery, web routing, ownership proof, or unknown. Unknown records stop the cutover. For each known record, name one owner and define the check that proves its consumer observed the state.

Then run the old and new workflows against a non-critical property-management tenant. Verify mail policy separately from application ownership proof. Record successful checks in the intended-state table, schedule review, and only then move more zones.

Keep the process small. Five explicit columns that someone reviews beat a large automation layer nobody trusts. The durable advantage is not one fewer dashboard; it is being able to answer, quickly, which service depends on a record and what evidence allowed a user into a workspace.

References

Top comments (0)