Decision: disconnect the hostname without transferring trust
A customer disconnecting a custom domain is asking the SaaS product to stop using that hostname for their workspace. It is not authorizing the next person who types the same name to inherit the binding. Treat disconnection and reassignment as separate decisions, each with its own evidence.
This article proposes an offboarding contract for product and platform teams. Its small routing fixture checks eight states: two allow service and six deny it. The fixture executes an application predicate, not DNS propagation or a hosting provider's deletion API. It makes the decision visible before implementation details obscure it.
The practical gap to close in your product is the handoff between customer support, edge configuration and tenant routing. A support ticket saying "domain removed" can mean the UI row disappeared while the hostname still reaches an old workspace. Define which observable result that phrase promises.
Separate the records that have different owners
Keep an application binding from normalized hostname to tenant, the provider's hostname identifier and the current ownership-verification generation. Record the state of each. The DNS record belongs to whoever controls the customer's zone. A certificate has another lifecycle again.
| Record | Offboarding question | Evidence to retain |
|---|---|---|
| Application binding | Can this hostname still select the old workspace? | Routing decision and binding generation |
| Provider hostname | Has the edge configuration been removed? | Provider identifier and observed status |
| Customer DNS | Does the hostname still target this service? | Observation time and customer instruction |
| Ownership proof | Can an old challenge authorize a new assignment? | Challenge generation, tenant and expiry |
Cloudflare's removal guidance explicitly tells SaaS providers to remove a churned customer's custom hostname. It distinguishes domains using Cloudflare from those using other DNS providers. That is a provider-specific operation to verify, not something deleting a row in your own database accomplishes. Cloudflare: remove custom hostnames.
Do not store an eternal Boolean called verified and reuse it for later tenants. Store the relationship that was verified. A challenge for one assignment is evidence about that assignment, not a transferable entitlement.
Make disconnected traffic unambiguous
Once disconnection takes effect in the application, requests arriving through the old hostname should receive the defined inactive-domain response. They should not fall back to a default customer workspace. Authenticate users independently of the hostname and resolve the tenant from trusted server-side state.
The edge may stop serving the name before your application sees another request. That still leaves a useful defense in the application if a stale route reaches it. Test both paths: direct hostname traffic through the provider and a controlled application routing test. An HTTP status by itself is insufficient if the response body contains the old tenant's content.
Decide what a signed-in user sees when the domain disconnects. A canonical product URL can provide a recovery route if the user still has workspace access. Avoid constructing redirects from arbitrary Host headers. Review authentication callbacks and cookie scope as explicit follow-up work. This fixture does not exercise either.
Require new evidence when the domain returns
In the example, tenant A used generation 1. A later assignment to tenant B uses generation 2. An active-looking record is still denied if it carries A's proof or the old generation. Only a matching current assignment can pass the predicate.
Cloudflare documents pre-validation using a DNS TXT record or an HTTP token when moving a hostname. That provides an example of obtaining fresh control evidence before switching traffic. Your application's tenant assignment must also be checked. Provider validation does not decide which of your workspaces a user may administer. Cloudflare: hostname pre-validation.
A proof should expire and be bound to the exact normalized hostname and intended tenant. Generate a fresh challenge rather than accepting a token copied from an old support conversation. Rate-limit verification attempts and keep ownership disputes out of automatic reassignment. These are proposed requirements for the real system, beyond the local predicate.
Inspect the eight routing decisions
Download the routing fixture and executed results. Run python3 experiment.py in a writable folder. The standard-library script writes its result beside itself and asserts each expected decision.
The original active assignment and the fresh matching assignment pass. Disabled and removed bindings fail. A pending new owner, an old proof, a proof for the wrong tenant and a foreign requester also fail. Inputs represent trusted application context. Passing a tenant ID from an untrusted request directly into this predicate would defeat its purpose.
This is deliberately smaller than a complete domain service. There is no DNS resolver, certificate manager or concurrent assignment transaction. In the real implementation, enforce uniqueness of the active hostname binding at the storage boundary and test two simultaneous claim attempts. Both request handlers must not independently conclude that the domain is available.
Acceptance: name the state support may promise
Use separate completion labels for application disconnection, provider removal and customer DNS cleanup. A customer who has not changed DNS may still have a dangling pointer even after your service stops serving their workspace. Tell them which record to remove without claiming you changed a zone you do not control.
- Confirm that old-host requests cannot read the previous tenant's content after the application cutoff.
- Observe the provider operation's final state, including a failed or retried deletion.
- Attempt reassignment with old proof and with proof for a different tenant. Both must fail.
- Complete a new claim using fresh evidence, then verify routing and workspace authorization together.
Assign an owner for unresolved DNS pointers and a bounded retention policy for binding history. Retain enough information to investigate an ownership dispute without keeping unnecessary customer data. The broader account closure and data export workflow handles the workspace lifecycle. Domain disconnection needs its own completion evidence.
Sources
Documentation checked .

Dreamtsoft Editorial
The routing fixture assumes its tenant context is trusted. An integration check should also prove that a caller cannot substitute another tenant identifier before the predicate runs.