Provider Quickstart

The private @phosra/link 0.7.10 candidate can be evaluated with synthetic parent, child, and platform fixtures. The Golden path explores replacing manual OAuth, trust, signing, endpoint minting, and retry wiring with one credential and three application adapters.

Private evaluation candidate. Public npm currently serves 0.6.1; the 0.7.10 code below is not a generally available production integration. Hosted routing, production credentials, and a production receipt rail remain roadmap. Contact the team about a bounded design-partner pilot.

What you build

  1. A server-only Link singleton imported by one same-origin catch-all route and one worker entry point.
  2. Adapters for your existing parent auth, child ownership, and policy facts.
  3. One durable worker process.
  4. The SDK-owned PhosraLink component in your parent UI.

Link owns the rest: environment and Trust List verification, platform discovery, signed Intent V2, public consent copy, OAuth handoff, durable delivery, retry, and evidence-based status.

1. Create the Golden server

ts
// lib/phosra-link-server.ts — server-only shared singleton
// Node-only module; never import from client components.
import { Pool } from "pg"
import { createGoldenLinkServer } from "@phosra/link/server"
 
export const phosraLinkServer = await createGoldenLinkServer({
  credential: process.env.PHOSRA_CREDENTIAL!,
  database: new Pool({ connectionString: process.env.DATABASE_URL }),
 
  authenticate: async (request) => {
    const session = await requireYourParentSession(request)
    return session === null ? null : {
      sessionID: session.id,
      parentID: session.parentId,
    }
  },
 
  children: {
    resolve: async ({ principal, childRef }) => {
      const child = await children.findOwned(principal.parentID, childRef)
      return child === null ? null : {
        id: child.id,
        displayName: child.name,
        ageBand: child.ageBand,
        householdRef: child.familyId,
      }
    },
  },
 
  policy: {
    resolve: ({ child, platformDid }) =>
      policies.rulesFor(child.id, platformDid),
  },
})

Then mount that same singleton in one catch-all route:

ts
// app/api/phosra/link/[...phosra]/route.ts
import { phosraLinkServer } from "@/lib/phosra-link-server"
 
export const GET = phosraLinkServer.handler
export const POST = phosraLinkServer.handler
export const DELETE = phosraLinkServer.handler

Use a v3 PHOSRA_CREDENTIAL. It carries the pinned environment authority; do not copy service URLs, trust roots, signing keys, or platform endpoints into browser code.

authenticate and children.resolve are authorization boundaries. A child reference from the request is only a lookup key. Return a child only after proving it belongs to the authenticated parent.

Household authority and Intent V2

Return a stable provider-local family identifier as householdRef. Link commits that value into a receiver-specific digest in the signed Intent V2. This enables safe one-to-many linking—for example, two children in one parental-controls household can share one Notflix Kids profile—without exposing the raw family ID to the browser or platform.

The platform still receives a separate, parent-authorized member for each child. Gatekeeper combines those members on the shared target and computes the effective policy. Your provider does not send a platform account ID or choose the merge algorithm.

No provider-owned sharing modal

If the parent selects an occupied profile from the same verified family, Gatekeeper's authorize handler owns the recommendation and explicit consent. It recommends a separate profile, explains strictest-rule aggregation and shared activity attribution, and offers Choose another profile, Confirm sharing, and Cancel and return in that order.

Keep the existing PhosraLink createSession, onEvent, and onExit contract. Do not pass family, child, platform-profile, target, or policy authority through browser props, and do not recreate the decision in your application. The initial screen identifies the authenticated platform catalog label recovered from the platform's server-side sealed catalog and the same-family member count. The signed selected-profile presentation follows token exchange; it is not the source of the confirmation label. Member names and numeric ages remain deferred until a future provider-signed member-display resolver is available.

2. Run the worker

ts
// phosra-link-worker.ts
import { phosraLinkServer } from "@/lib/phosra-link-server"
 
const shutdown = new AbortController()
process.once("SIGTERM", () => shutdown.abort())
process.once("SIGINT", () => shutdown.abort())
 
await phosraLinkServer.runWorker({ signal: shutdown.signal })

Run one loop. It serializes durable delivery and signed retry processing. Do not also schedule runWorkerOnce() in the same process while the loop is active.

tsx
import { PhosraLink } from "@phosra/link/react"
 
{open && <PhosraLink
  createSession={async ({ signal }) => {
    const response = await fetch("/api/phosra/link/sessions", {
      method: "POST",
      signal,
      headers: { "content-type": "application/json" },
      body: JSON.stringify({
        child_ref: selectedChildId,
        platform_did: selectedPlatformDid,
        return_to: window.location.pathname,
      }),
    })
    if (!response.ok) throw new Error("Unable to start Phosra Link")
    return response.json()
  }}
  onEvent={analytics.record}
  onExit={() => setOpen(false)}
/>}

Forward the AbortSignal exactly. The component owns the branded review, handoff, bounded polling, cancellation, retry, and restart-safe recovery.

4. Read status honestly

The session snapshot is the authority for parent-facing status:

StageSafe parent meaning
boundThe connection is durable; platform confirmation is pending.
rule_recordedControls were recorded; application is not yet confirmed.
profile_readyThe platform has the verified profile and results are being checked.
applied + E4Every requested control has current concrete platform evidence.
degradedSome controls are limited; a bounded retry may be offered.
refusedThe platform declined at least one required control.
stalePrior evidence is no longer current.
revokedProvider authority is revoked; release completion is tracked separately.

Never translate an HTTP 2xx, delivery acknowledgement, or adapter return into “controls active.”

5. Disconnect

Authorize the exact grant in your own tenant boundary, then call:

ts
import { phosraLinkServer } from "@/lib/phosra-link-server"
 
const authorizedGrant = await grants.requireForParent({ parentId, grantId })
 
const result = await phosraLinkServer.disconnectGrant({
  grantId: authorizedGrant.id,
  platformDid: authorizedGrant.platformDid,
  targetRef: authorizedGrant.targetRef,
})

Reuse the exact targetRef persisted with the issued grant. Never synthesize it from a raw child ID or householdRef: householdRef establishes authenticated provider-local family authority during issuance, while the saved targetRef binds this exact grant operation.

The returned snapshot proves provider-side revocation. Platform removal is complete only when releaseStatus becomes complete through the signed release lifecycle. See Disconnect & reconnect.

Design-partner pilot checklist

  • Keep PHOSRA_CREDENTIAL and Postgres server-only.
  • Mount GET, POST, and DELETE on the complete catch-all path.
  • Derive parent and child authority from your authenticated server session.
  • Use a stable, non-display householdRef.
  • Run one worker with graceful abort.
  • Render PhosraLink; do not replace its evidence language with optimistic copy.
  • Let the platform SDK own shared-profile confirmation; add no host modal or browser authority.
  • Log only your correlation IDs—never credentials, authorization URLs, or raw household identifiers.

For the complete API surface, see @phosra/link. Platform teams should use the Platform quickstart.