Which lane am I on? Look at your Phosra input.
createConnectReceiver (from @phosra/gatekeeper/next, v0.6.0+) collapses the OCSS connect
receiver to one route file and one allowlist. It verifies every delivery to the pinned
OCSS root — the same root your gatekeeper already pins to fetch enforcement profiles — so
the provider’s signature is the authentication. There is no shared HMAC secret to mint,
store, sync, or rotate.
The low-level
createGatekeeper() and every existing gatekeeper export are unchanged —
the enforce/confirm loop (refreshProfile → isAllowed → confirm) that pairs with this
receiver is documented on Platform Registration. This
page covers the connect leg the receiver handles.The entire receiver
/api/ocss/connect route. The provider’s Ed25519 signature, verified to
the root, is the auth; the allowlist is the authorization. Revoke a provider by removing its
DID from authorize — no key exchange, no rotation.
Publish the receiver before the first parent links
Adding the route to your app does not make it discoverable by Phosra Link. Complete the platform-registration step in the Phosra developer console (or with the signed registry API) before testing a parent flow:- Publish the OAuth surface (
authorize_url,par_url,token_url,profiles_url, scopes, and optional profile-management URL) through the platform connect-metadata operation. - Publish the delivery receiver through the separate platform endpoint-registration
operation. Do not put
connect_urlin the connect-metadata request; the two operations are deliberately separate so editing OAuth copy or URLs cannot silently rotate delivery credentials. - Store the endpoint-registration response in a secret manager immediately. It contains
one-time credential fields for compatibility lanes; never print the response, commit it, or
paste it into a build log. A signed-only
createConnectReceiverdoes not use the legacy HMAC secret at runtime, but registration still treats every returned credential as sensitive.
connect_url must be the exact public POST destination owned by your chosen
integration surface. For the low-level receiver on this page that is normally
https://your-app.example/api/ocss/connect; a platform using the Phosra Link Next.js facade may
instead expose a facade-owned route such as /api/phosra/delivery. Do not guess or copy another
platform’s path—use the route exported by the SDK surface you installed.
Verify discovery before opening the parent UI:
Config
How a delivery is verified — nothing you write
createConnectReceiver reads the raw request body once and dispatches by shape:
- Signed provision delivery (
isSignedProvisionDelivery(body)) →verifyProvisionDelivery→ create-or-adopt N age-banded profiles, thenonBoundper profile. This is the create-and-link fan-out from the provider. - Signed connect envelope /
{ endpoint_id_label, state }→handleConnect→ bind the single label, thenonBound(label, childRef). - Legacy
ocss-ext01/provision.v1HMAC batch → the HMAC lane — only whenlegacyHmacSecretis set.
did),
created-freshness (within createdSkewSec), and the authorize gate from the
verified envelope — all before your onBound runs. You verify nothing by hand.
onBound fires post-2xx, per bound label. On the batch path each call carries a
ProvisionContext so you know the age band and whether to auto-set an adult PIN; on the
single-bind path provision is undefined. A throwing onBound is routed to onError and
does not fail the delivery (the binding already landed).
After the connect leg — enforce
Receiving the connection is only the connect leg. The boundendpoint_id_label is your
profile-poll target: fetch and verify the signed enforcement profile, decide locally, and
confirm — all with the low-level @phosra/gatekeeper:
isAllowed → confirm loop (including the two-endpoint_id_label gotcha
and the fail-closed rules) is documented on
Platform Registration, the low-level createGatekeeper
page. (The Golden Platform Quickstart does not use this loop — its
createPlatform facade owns apply/observe internally.)
Trust-list liveness
Signed verification role-gates the signer to an active accredited enforcement-agent and verifies to root, so the connect leg now depends on Trust-List availability and accreditation freshness (the 7-day attestation TTL) — a coupling the old HMAC path never had. This is a deliberate trade, not a surprise: cache the last-known-good Trust List so a transient census blip doesn’t reject a legitimate, still-accredited provider. Name it in your ops runbook. See Migration → Liveness. When Phosra issues a production Link credential, it publishes the credential’s active Link public key and theenforcement-agent role atomically. There is no separate manual role grant
for the normal onboarding path; a conflicting pre-existing role makes issuance fail closed.
Branding is an assessed conformance item
Two parts, both checked at accreditation: (1) co-brand your OAuth leg — the authorize page the parent hits during the ceremony MUST readPhosra Link · <Platform>, never a bare
auth form; (2) provenance — once a profile is bound, surface a persistent “Managed via
Phosra” label on the managed account. See the
Phosra Link Branding Requirement.
What the provider (your partner) must do
Almost nothing new lands on the provider — the signed model is symmetric with what they already sign:- Add your platform DID to their
createLinkconnect target (they calllink.connect.finish/link.provisionwithplatformDid: "did:ocss:<you>"). - Deliver with their own writer key — no secret from you. If their delivery
401s, the fix is you adding their DID toauthorize, not a secret exchange. - That’s it. See Provider · createLink.
Next
- Platform Quickstart — the Golden path (
createPlatform), where a new platform starts - Provider · createLink (writer-plane compatibility) — the legacy sending side
- Migrating HMAC → Signed — retire your connect secret safely
- Platform Registration — the low-level
createGatekeeperenforce/confirm loop