@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.
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.
Before initPlatformOAuth builds an authorize URL, the SDK resolves the target
platform in two layers:
- 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.
- 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.