Skip to main content
@phosra/link is the writer-plane SDK. It runs in a provider’s backend (a parental-controls app’s server), signs everything locally over RFC 9421, and posts to the hosted OCSS census. If you are integrating end-to-end, start with the Provider quickstart — this page is the package reference for the pieces the quickstart doesn’t cover in depth: platform resolution and parent sessions.
npm install @phosra/link

LinkConfig

import type { LinkConfig } from '@phosra/link';
import pg from 'pg';

const config: LinkConfig = {
  censusBaseUrl:    'https://phosra-api-sandbox-production.up.railway.app', // production sandbox — canonical testing endpoint
  trustRootXB64Url: 'CMHWy3vUAiEcYDdE_bDvkRuEqwxkklS0tV-TYHJTlWU', // sandbox trust-root public key X (see note below)
  parentKey:        { seed: parentSeed, keyID: 'did:ocss:household-acme#parent-key-2026' },
  writerKey:        { seed: writerSeed, keyID: 'did:ocss:your-org#writer-key-2026' },
  writerDid:        'did:ocss:your-org',
  routerDid:        'did:ocss:phosra-router',
  householdSecret:  process.env.HOUSEHOLD_SECRET!,  // never sent to the census
  parentSessionSecret: process.env.PARENT_SESSION_SECRET, // enables verified parent sessions
  pool: new pg.Pool({ connectionString: process.env.LINK_DB_URL }),
  developerOrgId:   process.env.PHOSRA_DEV_ORG_ID,  // billing attribution — optional, see note below
};
trustRootXB64Url above (CMHWy3vUAiEcYDdE_bDvkRuEqwxkklS0tV-TYHJTlWU) is a PUBLIC key, pinned here out-of-band — that’s the point of root verification: you don’t fetch the trust root from the same census you’re about to verify. It’s safe to hardcode or check into your own config. developerOrgId (a phosra_live_...-issued org) is billing-attribution only — the quickstart above runs correctly without one; omit it and the family lands in the anonymous/self-host bucket (no invoice, no SLA).
The SDK is free and open (MIT). Signing and verification happen locally; billing is enforced server-side against your org — never inside this package, and never on the safety path.

How platforms are resolved

Before initPlatformOAuth builds an authorize URL, the SDK resolves the target platform in two layers:
  1. OCSS Trust List — the trust gate. The signed trust list at /.well-known/ocss/trust-list is fetched and verified against the trust root. The platform’s DID must be an active, unexpired entry. Absent, suspended, revoked, or expired all fail closed — you cannot connect a child to a non-accredited platform, and the next layer is never consulted.
  2. Phosra connect registry — the mechanics. The platform’s OAuth authorize/token/profiles endpoints come from GET /providers/{did}/connect, a Phosra product endpoint. It is deliberately not part of the signed OCSS document: the standard stays vendor-neutral (trust, keys, accreditation); connection mechanics are Phosra’s concern as the OCSS implementor.
Both layers run inside initPlatformOAuth/completePlatformOAuth; you don’t call them directly. A 404 from the connect registry surfaces as link/provider: no Phosra connect config for <did>.

Parent sessions

The parent authenticates with your app’s own auth — Phosra never sees parent credentials. What the SDK needs is a trustworthy binding between your authenticated parent session and the OAuth ceremony, so one parent’s state can never be completed by another parent, and an expired login cannot finish a ceremony it started. Verified mode (recommended). Set parentSessionSecret in LinkConfig. After your login succeeds, issue a signed, expiring token server-side and pass it as parentSessionRef on all three ceremony legs (an HttpOnly; Secure cookie works well):
import { issueParentSession } from '@phosra/link';

// at login time, server-side:
const token = issueParentSession(process.env.PARENT_SESSION_SECRET!, {
  parentId: user.id,          // your stable parent identifier
  ttlMs: 30 * 60 * 1000,      // default 30 minutes
});
The SDK verifies the token (HMAC + expiry, fail closed) on initPlatformOAuth, completePlatformOAuth, and bindProfile, and binds the ceremony to the verified session id — a re-issued token for the same session still completes, an expired one does not, and another parent’s valid token is rejected. BYO mode. Leave parentSessionSecret unset and pass your own server-side session identifier as parentSessionRef (as the Provider quickstart shows with req.session.id). The contract: derive it server-side from your authenticated session; never accept it from the client.

Reference BFF

A complete, framework-free reference implementation of the three connect routes — including the login cookie wiring — lives in the repo at packages/link/examples/reference-bff, with an end-to-end test that drives the full ceremony over real HTTP.

Beyond connect

The ceremony, rule writes (directive), and family-wide fan-out (convergeFamily) are covered step-by-step in the Provider quickstart. For the platform side of the handshake, see the Platform quickstart. The protocol primitives themselves are @openchildsafety/ocss, re-exported by the Phosra Developer SDK — Phosra implements the standard; it does not own it.