Disconnect & reconnect

Disconnect is a signed lifecycle, not a row deletion or an optimistic UI toggle. The provider first revokes its test authority; the sandbox Gatekeeper then updates or releases the synthetic platform target so you can observe the result.

Disconnect an authorized grant

Use the Golden Link server after re-authorizing the exact grant against your own parent and tenant boundary:

ts
const projection = await server.disconnectGrant({
  grantId: authorizedGrant.id,
  platformDid: authorizedGrant.platformDid,
  targetRef: authorizedGrant.targetRef,
})
 
if (projection === null) {
  return new Response("Not found", { status: 404 })
}

The tuple { grantId, platformDid, targetRef } is deliberate. Load the persisted grant for the authenticated parent and reuse its exact saved targetRef; do not reconstruct it from a child ID, householdRef, display value, or browser body. householdRef proves provider-local family authority during issuance, while the saved grant targetRef is the exact authority required for this grant operation.

projection.snapshot.stage === "revoked" proves that provider-side authority is revoked. It does not by itself prove the platform removed controls. Use projection.releaseStatus for that second fact.

releaseStatusParent-facing meaning
pending“Disconnected—waiting for the platform to confirm removal.”
complete“Disconnected.” The exact signed release was durably acknowledged.

Keep the Link worker running so the release event, retry, acknowledgement, and platform evidence can converge after the HTTP request finishes.

The Golden Gatekeeper runtime performs one additional safety exchange automatically during final release. It records the platform's exact last verified profile authority with Phosra, then fetches the final router-signed tombstone. The tombstone must match the Link, child, selected profile, lifecycle generation, and predecessor artifact before the platform release adapter can run. Do not recreate this request in application code; upgrade @phosra/gatekeeper and keep its worker running.

Shared-profile behavior

One platform profile may represent multiple independently linked children. For example, Ramsay and Coldy can share one Notflix Kids profile.

Disconnecting Ramsay while Coldy remains is a partial removal:

  1. Ramsay's member is revoked.
  2. Gatekeeper computes the effective policy for the remaining member.
  3. The platform receives an aggregate apply operation.
  4. Your adapter applies and observes the remaining policy.
  5. Native profile settings are not restored.

Disconnecting Coldy afterward is the final release:

  1. The last member is revoked.
  2. Gatekeeper sends an aggregate release operation.
  3. Your adapter removes the Phosra-managed overlay.
  4. observeRelease confirms removal independently.
  5. Native profile settings are restored.

Do not equate “one child disconnected” with “release the platform profile.” The SDK's opaque targetOperation and generation fencing tell Gatekeeper which lane is authorized; application code must preserve the provided idempotency key and must not forge or clone that authority.

Decline and cancel are not disconnect

  • Decline: the parent does not authorize the platform handoff. No active grant exists to release.
  • Cancel before binding: Link retires the time-limited ceremony and its recovery locator.
  • Close after a durable binding: the connection remains; Link preserves the recovery state while platform evidence converges.
  • Disconnect: an existing grant is revoked and the signed release lifecycle begins.

Let PhosraLink handle callback errors, cancellation, expiry, and recovery. Do not manually exchange an OAuth code after the server session reports decline or terminal cancellation.

Reconnect

Reconnect by opening a new PhosraLink ceremony for the same authenticated child and platform:

tsx
<PhosraLink
  createSession={({ signal }) => fetch("/api/phosra/link/sessions", {
    method: "POST",
    signal,
    headers: { "content-type": "application/json" },
    body: JSON.stringify({
      child_ref: child.id,
      platform_did: platform.did,
      return_to: window.location.pathname,
    }),
  }).then(async (response) => {
    if (!response.ok) throw new Error("Unable to reconnect")
    return response.json()
  })}
  onEvent={recordLinkEvent}
  onExit={closeLink}
/>

The new ceremony creates fresh signed authority, state, and replay boundaries. Never reuse an old authorization code, state value, endpoint label, or browser recovery object.

For a shared target, reconnecting a previously removed child adds a new member generation and recomputes the effective profile. It does not create a second copy of the platform profile unless the parent selects a different platform profile during authorization.

Operational verification

Provider applications can read the exact grant projection with getSnapshotForGrant(...). Platforms can read the privacy-projected shared-target feed with phosra.readTopology().

During partial removal, expect an active target with one revoked member and at least one active member. The signed v2 release acknowledgement for the removed member reports nativeRestored: false; this is successful partial removal, not a degraded release. During final release, expect state: "released", zero active members, and nativeRestored: true. Topology aliases are opaque and must not be joined to product identifiers.

Checklist

  • Re-authorize the grant tuple on the server before disconnecting.
  • Show provider revocation separately from platform release completion.
  • Keep workers running after the request returns.
  • Preserve controls during partial removal from a shared profile.
  • Restore native settings only after final release.
  • Start reconnect as a new ceremony; reuse no old OAuth or recovery material.
  • Base success copy on signed lifecycle evidence, not HTTP status.

See @phosra/link, the Provider quickstart, and the Platform quickstart.