@phosra/link
@phosra/link 0.7.35 is the provider-side SDK candidate for Phosra Link. The recommended
integration is a server-only v3 credential, one same-origin catch-all route, one
durable worker, and the mandatory-branded React component.
Private evaluation candidate. Public npm currently serves 0.6.1;
@phosra/[email protected] is not a generally available production integration.
Hosted routing, production credentials, and a production receipt rail remain
roadmap.
npm install @phosra/[email protected]@phosra/link is ESM-only. The Golden server is Node-only and must be imported
from @phosra/link/server. Never import credentials or server APIs into a client
component.
Recommended architecture
Your application owns only its existing parent authentication, child lookup, and policy facts. Link owns environment discovery, trust verification, signed Intent V2 creation, public consent copy, OAuth handoff, durable delivery, retries, and evidence-based status.
// 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 authenticatedParent(request)
return session === null ? null : {
sessionID: session.id,
parentID: session.parentId,
}
},
children: {
resolve: async ({ principal, childRef }) => {
const child = await childForParent(principal.parentID, childRef)
return child === null ? null : {
id: child.id,
displayName: child.displayName,
ageBand: child.ageBand,
householdRef: child.familyId,
}
},
},
policy: {
resolve: ({ child, platformDid }) =>
policyRulesFor(child.id, platformDid),
},
})Import that singleton from the catch-all route. The route contains no credential or environment configuration of its own:
// 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.handlerThe catch-all is important. It serves the callback, session creation and status,
retry/cancel, and signed platform-event receiver under /api/phosra/link/*.
Mounting only the callback breaks recovery and prevents later platform evidence
from reaching the provider.
The authenticated householdRef boundary
householdRef is your stable, provider-local family authority. Return it only
after authenticating the parent and proving that the child belongs to that
parent. The SDK derives a platform-scoped digest for signed Intent V2. The raw
value is not a browser input and is not sent to the platform.
Never use a display name, email address, or client-supplied family ID as
householdRef.
Shared-profile consent preserves the host contract
An occupied same-family platform profile does not add a provider API or React state for the host to implement. The Golden Gatekeeper authorize handler recommends a separate profile and presents Choose another profile, Confirm sharing, and Cancel and return in that order. It explains that the strictest combined protections apply and that shared activity cannot be reliably attributed to one child.
Before token exchange, the handler displays only the authenticated platform catalog label recovered from its server-side sealed catalog and the verified same-family member count. The signed selected-profile presentation follows token exchange. It does not expose raw platform IDs, family/child authority, target or aggregate identifiers, or policy parameters; forms carry only bounded opaque tokens. Names and numeric ages of existing members require a future provider-signed member-display resolver and are not claimed by this release.
Run the durable worker
Run exactly one worker loop in a worker process and abort it during graceful shutdown:
// phosra-link-worker.ts — separate server process entry point
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 })The worker serializes delivery and retry work. A successful HTTP response means a verified receiver acknowledgement, not that every control is applied. Parent status advances only when signed platform evidence supports it.
Render the parent experience
import { PhosraLink } from "@phosra/link/react"
<PhosraLink
createSession={async ({ signal }) => {
const response = await fetch("/api/phosra/link/sessions", {
method: "POST",
signal,
headers: { "content-type": "application/json" },
body: JSON.stringify({
platform_did: selectedPlatformDid,
child_ref: selectedChildId,
return_to: window.location.pathname,
}),
})
if (!response.ok) throw new Error("Unable to start Phosra Link")
return response.json()
}}
onEvent={recordLinkEvent}
onExit={closeLink}
/>Forward the supplied signal. Link cancels abandoned session creation, supports
restart-safe same-tab recovery, polls bounded server-authoritative status, and
never turns a delivery acknowledgement into a fake success state.
PhosraLinkDialog remains an alias for source compatibility. New code should use
the shorter PhosraLink export.
Shared-profile confirmation preserves the same createSession, onEvent, and
onExit behavior. Do not wrap the component in a second consent modal.
Server API
| Member | Purpose |
|---|---|
ready() | Verify the environment and ensure package-owned schema is ready. The Golden factory calls this before it returns. |
handler | Fetch-standard handler for the GET, POST, and DELETE catch-all exports. |
runWorkerOnce() | Perform at most one bounded, non-idle delivery or retry action. |
runWorker({ signal }) | Drain durable work serially until the signal aborts. |
getSnapshotForGrant(authority) | Read the verified public projection for an app-authorized grant. |
retryPlatformForGrant(authority) | Schedule one signed, durable platform refresh for the exact saved or disconnect-pending connection after re-authorizing it against your tenant. |
disconnectGrant(authority) | Record provider-side revocation and begin the signed platform release lifecycle. |
Grant reads and disconnects require the exact app-authorized tuple
{ grantId, platformDid, targetRef }. Do not accept that tuple directly from an
untrusted browser without re-authorizing it against your own tenant boundary.
Let a parent refresh an existing connection
When a platform reports degraded, stale, or a previously applied result that
needs to be checked again, do not create another Link ceremony. The same method
also resumes an exhausted profile refresh after disconnectGrant() so the
platform can fetch the signed revocation tombstone and finish its release.
Re-authorize the child and exact active or disconnect-pending grant in your own
database, then pass only that exact tuple to the SDK:
const authority = {
grantId: savedConnection.grantId,
platformDid: savedConnection.platformDid,
targetRef: `child:${authorizedChild.censusRef}`,
}
const projection = await phosraLinkServer.retryPlatformForGrant(authority)
if (projection === null) throw new Error("Platform sync is not available")The method records a signed retry request in the provider outbox. The existing
runWorker() process delivers it, and Gatekeeper independently checks current
grant authority before reopening only a failed degraded or stale profile
lifecycle. A signed revocation request cannot reopen healthy or unrelated
authority. A healthy shared-profile aggregate and its other child memberships
remain intact. Keep the last verified state visible while the refresh runs;
label the parent action with plain copy such as Sync now or
Check disconnect.
If the platform is unreachable for the request's five-minute validity window, the request becomes immutable expired evidence. A later authorized parent check mints the next signed retry epoch; repeated checks while a request is still active reuse that exact request rather than creating parallel work.
Evidence states are intentionally different
boundmeans a durable connection exists.rule_recordedmeans requested controls were recorded, not applied.profile_readymeans the platform has a verified profile and results are being checked.appliedwithE4means every requested control has current concrete platform evidence.degraded,refused, andstaleremain visible; the SDK does not paint them green.revokedmeans the provider authority is revoked. Platform removal is complete only after the signed release lifecycle confirms it.
Advanced compatibility API
createLink(...) and the low-level ceremony functions remain available for older
writer-plane integrations. They are not the recommended durability boundary for a
new parent application. New integrations should begin with
createGoldenLinkServer(...) and PhosraLink.
See the Provider quickstart, branding contract, and disconnect guide.