DEV Community

ZylahMorn61835
ZylahMorn61835

Posted on

Domain Verification Actually Proves DNS Control Before Marketplace Cutover

Short answer: domain verification actually proves DNS control at observation time; it does not prove authorisation to represent the business. Hold onboarding at that boundary, record the evidence, and choose a cutover policy that makes propagation delay explicit.

A marketplace should treat DNS verification as proof of control over a named DNS zone, not as proof that the requester is authorized to act for a company. The distinction is easy to state and easy to lose in an onboarding state machine.

The distinction matters when a seller brings pay.example to a marketplace. A TXT token visible at the expected name proves that someone who can change the zone published the token. It does not prove that the seller owns the trademark, has a contract, or may receive payments for the business behind the name. Those are separate authorization checks.

What does domain verification actually prove about DNS control?

The verifier has a narrow claim: at observation time, a resolver could obtain a value that matches a nonce issued to this onboarding attempt. That claim has a useful audit shape: subject, token hash, queried name, resolver path, observed answer, and timestamps. It is deliberately weaker than identity.

Three checks.

In payment and ledger systems, I model the token as a one-time capability. The database transition is idempotent: repeating a callback or a poll can only move pending to dns_control_confirmed once. An audit record keeps the original observation even after the TXT record is removed. This avoids the common mistake of treating current DNS state as a permanent authorization grant.

DMARC makes the same conceptual boundary visible. Its policy is published in DNS, but policy publication does not establish who is entitled to send mail for a legal entity; it supplies a machine-readable assertion that receivers evaluate (RFC 7489).

Which cutover policy survives propagation delay?

The key decision is not a magic timeout. It is the failure boundary accepted by the marketplace.

Policy Strength Cost and failure mode
Single resolver observation Fast onboarding Caches or split-horizon DNS can produce a false negative
Quorum of independent recursive resolvers Better evidence across regions Adds waiting and operational dependencies
Authoritative-server query plus recursive checks Separates publication from cache visibility Requires careful handling of DNS provider behavior
Recheck at activation Limits stale evidence Delays the first live request if propagation changed

For a seller onboarding flow, I use an initial observation to show progress, then require a bounded quorum before activation. The quorum is a policy choice documented with the risk owner; it is not a claim that DNS has an exactly-once delivery guarantee. A timeout should produce verification_expired, not an authorization success, and a later retry must use a fresh nonce.

The freshness window must be visible in the record. A five-minute nonce lifetime and a 30-minute operational retry budget are different controls; combining them makes incident review ambiguous. Teams should also test negative answers, because a cached NXDOMAIN can outlive the moment when the seller fixed the record.

The critical path in code

The following Go sketch keeps verification and authorization as different state transitions. The repository interface can be backed by any SQL store, and the resolver client can be replaced in tests.

package verify

import (
    "context"
    "crypto/sha256"
    "encoding/hex"
    "errors"
    "time"
)

type Observation struct {
    Name, Value, Resolver string
    ObservedAt time.Time
}

type Store interface {
    GetAttempt(ctx context.Context, id string) (string, string, error)
    ConfirmControl(ctx context.Context, id, digest string, o Observation) error
}

func ConfirmDNSControl(ctx context.Context, store Store, attemptID string, o Observation) error {
    name, expected, err := store.GetAttempt(ctx, attemptID)
    if err != nil { return err }
    if o.Name != name || o.Value != expected { return errors.New("token mismatch") }

    sum := sha256.Sum256([]byte(o.Value))
    digest := hex.EncodeToString(sum[:])
    // ConfirmControl must be idempotent on attemptID.
    return store.ConfirmControl(ctx, attemptID, digest, o)
}
Enter fullscreen mode Exit fullscreen mode

The verifier should log the resolver identity and response code, but avoid storing unrelated query data. Metrics should separate timeout, NXDOMAIN, SERVFAIL, and token mismatch; collapsing them into verification_failed hides whether the remedy is waiting, correcting a record, or investigating abuse.

It failed once in review.

The cause was not cryptography; it was a state transition that accepted a late observation for an already expired attempt. The repair was to compare the observation timestamp with the attempt deadline inside the same transaction that writes the audit event. That small ordering rule is more valuable than another dashboard.

What I rejected, and when it is valid

I rejected a single authoritative lookup as the activation gate. It is attractive because it is quick and avoids recursive-cache variance, yet it can certify publication before customers in another region can resolve the record. That is a poor fit for a marketplace cutover where checkout traffic arrives globally.

The approach is valid for a low-risk preview URL, an internal staging environment, or a workflow whose next step is itself a propagation wait. Its limitation is decisive: it is not a substitute for legal or account authorisation. Keep those checks explicit, with separate owners and audit events, so a successful DNS observation cannot be replayed as permission to move money.

That is the boundary I would explain to compliance reviewers: control is technical evidence; authorisation is a business decision.

Publish a short-lived nonce, observe it through independent recursive paths, and activate only after the documented quorum and freshness window pass. Store the observation as evidence of DNS control, then run identity, contract, and payment-risk authorization as separate idempotent transitions. This keeps cutover speed measurable without confusing a technical capability with the right to exercise it.

References

Top comments (0)