Connect a platform

A platform (also called a provider) is anything Phosra can push a child-safety policy to — a DNS filter, a router, an app, an operating system. Before Phosra can enforce anything, a parent has to connect the platform and approve sharing their children's profiles.

This guide walks the full connect ceremony — discovery → consent → token → profiles — against the public sandbox. Every request and response below is verbatim live output, captured while writing this page. No API key, nothing to install.

The four calls chain end to end: discover the endpoints (GET /providers/{did}/connect) → send the parent to consent (authorize_url) → exchange the returned code for a token (token_url) → read the approved profiles (profiles_url). Each step below carries a Fields & errors reference you can expand.

Sandbox-first. The reference provider used here — did:ocss:loopline — is seeded into the partner sandbox at https://phosra-api-sandbox-production.up.railway.app. Nothing you connect there touches a real family. This guide does not provide a production OCSS routing endpoint; hosted routing and the production receipt rail remain roadmap.

Before you start

Set the base URL once so every step is copy-paste:

bash
export PHOSRA_BASE="https://phosra-api-sandbox-production.up.railway.app"

You will connect the sandbox's synthetic reference provider, Loopline (did:ocss:loopline). Its Trust List entry and OAuth surface are test fixtures, not an accredited organization or evidence of a production provider.

  1. 1
    Discover the provider's connect endpoints

    Every connectable provider publishes its OAuth endpoints at GET /providers/{did}/connect. Start there — never hard-code the URLs.

    bash
    curl -s "$PHOSRA_BASE/api/v1/providers/did:ocss:loopline/connect"

    Real response (200):

    json
    {
      "authorize_url": "https://phosra-api-sandbox-production.up.railway.app/oauth/authorize",
      "token_url": "https://phosra-api-sandbox-production.up.railway.app/oauth/token",
      "profiles_url": "https://phosra-api-sandbox-production.up.railway.app/oauth/profiles",
      "scopes": ["child_profiles.read"],
      "name": "Loopline"
    }

    A known sandbox fixture that has not configured a connect surface returns 404 provider connect config not available. did:ocss:courier is deliberately left unconfigured so you can test that branch.

  2. 2
    Send the parent to the consent page

    Redirect the parent's browser to authorize_url with your client_id (the provider DID), a redirect_uri, and an opaque state you generate:

    code
    GET /oauth/authorize
          ?client_id=did:ocss:loopline
          &redirect_uri=https://loopline.example/callback
          &state=xyz789
          &response_type=code
    

    The sandbox serves a real consent screen. The parent sees exactly which child profiles they are about to share, and chooses Approve or Deny:

    Phosra sandbox consent page titled 'Connect your family to this app?' listing Mia, Leo, and Ava as child profiles, with Approve and Deny buttons
    The live sandbox consent page for did:ocss:loopline — captured from the running server, not a mockup.

    This consent page is a sandbox demo, not a production IdP. The census's reference authorize surface auto-approves the seeded test family (Mia/Leo/Ava) with no login — a sandbox affordance, gated to PHOSRA_ENV=sandbox. A production design would require the provider to host its own authenticated authorization surface and return non-synthetic profiles under its own reviewed data-handling controls. No public production census or customer deployment is claimed here.

  3. 3
    Receive the authorization code

    On Approve, Phosra redirects back to your redirect_uri with a short-lived code and the state you sent (verify it matches before continuing):

    code
    302 Location: https://loopline.example/callback?code=sbxauth_REDACTED_ONE_TIME_CODE&state=xyz789
    

    On Deny, no code is issued — you get ?error=access_denied&state=… instead. Handle both. See Disconnect & reconnect for the decline path in full.

  4. 4
    Exchange the code for an access token

    Trade the code for a bearer token at token_url:

    bash
    curl -s -X POST "$PHOSRA_BASE/oauth/token" \
      -H "Content-Type: application/json" \
      -d '{
        "grant_type": "authorization_code",
        "code": "$SANDBOX_AUTHORIZATION_CODE",
        "client_id": "did:ocss:loopline",
        "redirect_uri": "https://loopline.example/callback"
      }'

    Example response (200; token redacted):

    json
    {
      "access_token": "REDACTED_SANDBOX_ACCESS_TOKEN",
      "expires_in": 3600,
      "scope": "profiles",
      "token_type": "Bearer"
    }

    On the scope value. Discovery advertises the requested scope as child_profiles.read (the canonical name), while the issued token echoes the short form scope: "profiles". Both name the same grant — read-only access to the approved children. Key your logic off the token you were issued, not off a hard-coded string, and treat the two as equivalent.

  5. 5
    Read the shared child profiles

    Call profiles_url with the token. You get back exactly the children the parent approved — each with a stable subject_ref you use for policy and enforcement calls:

    bash
    curl -s "$PHOSRA_BASE/oauth/profiles" \
      -H "Authorization: Bearer $SANDBOX_ACCESS_TOKEN"

    Real response (200):

    json
    [
      { "id": "mia", "displayName": "Mia", "subject_ref": "a11ce0fa-0000-4000-8000-0000000000a1", "kind": "child" },
      { "id": "leo", "displayName": "Leo", "subject_ref": "a11ce0fa-0000-4000-8000-0000000000a2", "kind": "child" },
      { "id": "ava", "displayName": "Ava", "subject_ref": "a11ce0fa-0000-4000-8000-0000000000a3", "kind": "child" }
    ]

    The platform is now connected. Hold onto each subject_ref — that is the handle you pass to the policy and enforcement endpoints in Set up a family & kids.

Which platform supports which rule?

Not every platform can enforce every rule. Discovery endpoints let you pick the right one before you ask a parent to connect:

bash
# Every platform that can do DNS-level web filtering
curl -s "$PHOSRA_BASE/api/v1/platforms/by-capability?capability=web_filtering"
# → [ "fire_tablet", "apple", "microsoft", "cleanbrowsing", "controld", "nextdns" ]

Check each synthetic platform record's enforcement_mode to exercise mode-aware UI. These fixture values do not prove a working adapter. See Platforms & enforcement modes.

Beyond sandbox evaluation

The OAuth ceremony above is a synthetic reference flow. Production counterparties, credentials, hosted routing, broader adapters, and receipt infrastructure remain roadmap. Apply as a design partner to define a bounded pilot.

Next steps