# docs/internals/t3-code-connect-auth-flow.html · stienswout/t3code

[View on GitCafe](https://git.cafe/stienswout/t3code/blob/main/docs/internals/t3-code-connect-auth-flow.html)

Repository: [stienswout/t3code](https://git.cafe/stienswout/t3code)

Visibility: public

Requested revision: refs/heads/main

Commit: f39dd8dfaa635f213a82dea1e7f4737b5510f4e4

Blob: 038132ee5cbfee126b30e602f2fb3d5e66c05c66

Size: 43466 bytes

[Immutable source](https://git.cafe/stienswout/t3code/blob/f39dd8dfaa635f213a82dea1e7f4737b5510f4e4/docs/internals/t3-code-connect-auth-flow.html?format=markdown)

```
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>T3 Connect Architecture</title>
    <style>
      :root {
        color-scheme: light;
        --ink: #171717;
        --muted: #62646b;
        --hairline: #d8d8dd;
        --panel: #ffffff;
        --paper: #f5f5f2;
        --blue: #1457d9;
        --green: #1d7d4d;
        --amber: #a65f00;
        --red: #b8242c;
        --violet: #6150b8;
        --shadow: 0 18px 55px rgba(25, 25, 28, 0.08);
      }

      * {
        box-sizing: border-box;
      }

      body {
        margin: 0;
        background:
          linear-gradient(90deg, rgba(0, 0, 0, 0.035) 1px, transparent 1px),
          linear-gradient(rgba(0, 0, 0, 0.035) 1px, transparent 1px), var(--paper);
        background-size: 34px 34px;
        color: var(--ink);
        font-family:
          ui-sans-serif,
          -apple-system,
          BlinkMacSystemFont,
          "Segoe UI",
          sans-serif;
        line-height: 1.48;
      }

      .shell {
        width: min(1540px, calc(100vw - 40px));
        margin: 0 auto;
        padding: 38px 0 72px;
      }

      header {
        border-bottom: 2px solid var(--ink);
        padding-bottom: 24px;
        margin-bottom: 28px;
      }

      .eyebrow {
        color: var(--blue);
        font-size: 12px;
        font-weight: 800;
        letter-spacing: 0.08em;
        text-transform: uppercase;
      }

      h1 {
        max-width: 980px;
        margin: 8px 0 12px;
        font-size: clamp(34px, 5vw, 66px);
        line-height: 0.98;
      }

      h2 {
        margin: 0 0 14px;
        font-size: 26px;
        line-height: 1.08;
      }

      h3 {
        margin: 22px 0 8px;
        font-size: 17px;
      }

      p {
        margin: 0 0 12px;
      }

      code,
      .mono {
        font-family:
          ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
      }

      code {
        border-radius: 4px;
        background: #f0f0ed;
        padding: 1px 4px;
        font-size: 0.92em;
      }

      .lede {
        max-width: 1000px;
        margin: 0;
        color: var(--muted);
        font-size: 18px;
      }

      .grid {
        display: grid;
        grid-template-columns: repeat(12, 1fr);
        gap: 18px;
      }

      .panel {
        grid-column: span 12;
        border: 1px solid var(--hairline);
        border-radius: 10px;
        background: var(--panel);
        box-shadow: var(--shadow);
        padding: 22px;
      }

      .half {
        grid-column: span 6;
      }

      .callout {
        border-left: 5px solid var(--blue);
        background: #eef4ff;
        padding: 14px 16px;
        margin-top: 14px;
      }

      .callout.warning {
        border-left-color: var(--amber);
        background: #fff6e6;
      }

      .badge-row {
        display: flex;
        flex-wrap: wrap;
        gap: 8px;
        margin-top: 14px;
      }

      .badge {
        border: 1px solid var(--hairline);
        border-radius: 999px;
        background: #fff;
        padding: 5px 9px;
        font-size: 12px;
        font-weight: 700;
      }

      .badge.user {
        border-color: rgba(20, 87, 217, 0.3);
        color: var(--blue);
      }

      .badge.env {
        border-color: rgba(29, 125, 77, 0.3);
        color: var(--green);
      }

      .badge.local {
        border-color: rgba(166, 95, 0, 0.35);
        color: var(--amber);
      }

      .diagram {
        overflow-x: auto;
        margin: 12px 0 0;
        border: 1px solid var(--hairline);
        border-radius: 8px;
        background: #fbfbf8;
        color: var(--ink);
        padding: 18px;
      }

      .diagram svg {
        display: block;
        width: auto !important;
        min-width: 100%;
        max-width: none !important;
        height: auto;
        margin: 0 auto;
      }

      table {
        width: 100%;
        border-collapse: collapse;
        font-size: 14px;
      }

      th,
      td {
        border-bottom: 1px solid var(--hairline);
        padding: 11px 9px;
        text-align: left;
        vertical-align: top;
      }

      th {
        color: var(--muted);
        font-size: 12px;
        letter-spacing: 0.05em;
        text-transform: uppercase;
      }

      ul {
        margin: 8px 0 0;
        padding-left: 20px;
      }

      li + li {
        margin-top: 6px;
      }

      .flow {
        display: grid;
        gap: 10px;
        margin-top: 12px;
      }

      .step {
        border: 1px solid var(--hairline);
        border-left: 5px solid var(--green);
        border-radius: 8px;
        background: #fff;
        padding: 12px 14px;
      }

      .step strong {
        display: block;
        margin-bottom: 3px;
      }

      .source-list a {
        color: var(--blue);
        font-weight: 700;
      }

      @media (max-width: 860px) {
        .half {
          grid-column: span 12;
        }

        .shell {
          width: min(100vw - 24px, 1540px);
          padding-top: 24px;
        }
      }
    </style>
  </head>
  <body>
    <main class="shell">
      <header>
        <div class="eyebrow">Implemented architecture</div>
        <h1>T3 Connect Control Plane and Managed Endpoint Flow</h1>
        <p class="lede">
          T3 Connect links a locally authorized T3 environment to a signed-in cloud user, provisions
          a managed HTTPS/WSS endpoint for that environment, and brokers proof-bound remote
          connections. The local environment remains the authority that issues environment access
          credentials. The hosted relay stores links, reconciles managed endpoint resources,
          validates signed proofs, and delivers agent-activity notifications.
        </p>
        <div class="badge-row">
          <span class="badge user">Client -> Relay: Clerk bearer or relay DPoP</span>
          <span class="badge env">Relay -> Environment: relay-signed health and mint proofs</span>
          <span class="badge env"
            >Environment -> Relay: environment bearer plus signed activity proof</span
          >
          <span class="badge local">Client -> Environment: environment access token plus DPoP</span>
        </div>
      </header>

      <section class="grid" aria-label="Architecture summary">
        <article class="panel half">
          <h2>Security Invariant</h2>
          <p>
            A cloud identity is not an environment login. Remote access requires all of the
            following:
          </p>
          <ul>
            <li>a Clerk-authenticated T3 Connect user;</li>
            <li>an active relay link for that user and environment;</li>
            <li>a DPoP proof key held by the remote client;</li>
            <li>a relay-signed mint request accepted by the linked local environment; and</li>
            <li>an environment-issued credential bound to the remote client's DPoP thumbprint.</li>
          </ul>
          <div class="callout">
            The relay cannot mint an environment access token by itself. It can only ask the local
            environment to mint a short-lived bootstrap credential for an authorized cloud user.
          </div>
          <p>During an honest connection flow, the relay cannot act as the remote client:</p>
          <ul>
            <li>
              Normal environment API traffic goes directly from the remote client through the
              managed endpoint. The relay does not receive the resulting environment access token.
            </li>
            <li>
              The one-time bootstrap credential and resulting environment access token are bound to
              the remote client's DPoP public-key thumbprint. Redeeming or using them requires
              request proofs signed by the corresponding private key, which stays on the client.
            </li>
            <li>
              Relay-signed health and mint proofs are short-lived, audience-bound, scoped, and
              replay-guarded. They are accepted only by the narrow cloud endpoints, not as normal
              environment API credentials.
            </li>
            <li>
              Environment health and mint responses are signed by the linked environment and bound
              to the request nonce, so a different process behind the tunnel cannot impersonate the
              linked environment.
            </li>
          </ul>
          <div class="callout warning">
            The hosted relay remains a trusted mint broker: it holds the cloud-mint signing key.
            DPoP prevents credential reuse by the relay or tunnel transport during an honest flow,
            but it does not make compromise of the relay signing authority harmless.
          </div>
        </article>

        <article class="panel half">
          <h2>Product Boundaries</h2>
          <p>
            The generic local connector is called the <strong>relay client</strong>. The current
            implementation layer uses <code>cloudflared</code>, but that is an internal transport
            detail rather than the product contract.
          </p>
          <ul>
            <li>
              The relay Worker owns cloud links, managed endpoint allocations, and notifications.
            </li>
            <li>
              The environment server owns local sessions, environment keys, and access tokens.
            </li>
            <li>The relay client exposes only the environment's loopback HTTP server.</li>
            <li>
              Web and mobile clients connect directly to the managed environment endpoint after
              bootstrap.
            </li>
          </ul>
        </article>
      </section>

      <section class="panel" aria-label="Topology">
        <h2>Current Topology</h2>
        <pre class="diagram mermaid">
flowchart LR
  subgraph Clients["User-facing clients"]
    Web["Desktop / hosted web UI"]
    Mobile["Mobile app"]
    CLI["Headless CLI"]
  end

  Clerk["Clerk<br/>user identity and OAuth"]

  subgraph Relay["T3 Code Relay on Cloudflare"]
    Worker["Relay Worker<br/>HTTP API"]
    Queue["APNs delivery queue<br/>with dead-letter queue"]
    Hyperdrive["Hyperdrive"]
    CF["Cloudflare tunnel + DNS APIs"]
  end

  DB["PlanetScale Postgres<br/>prod database + stage branches"]
  APNs["Apple Push Notification service"]
  Traces["Axiom OTLP traces"]

  subgraph Local["Linked T3 environment"]
    Env["Environment server<br/>local auth authority"]
    RelayClient["Relay client<br/>cloudflared implementation"]
    Secrets["Server secret store<br/>keys + relay config"]
  end

  Endpoint["Managed HTTPS/WSS endpoint"]

  Web -->|"Clerk bearer / relay DPoP"| Worker
  Mobile -->|"Clerk bearer / relay DPoP"| Worker
  CLI -->|"Clerk OAuth bearer"| Worker
  Web --> Clerk
  Mobile --> Clerk
  CLI -->|"PKCE authorization code flow"| Clerk
  Worker --> Hyperdrive --> DB
  Worker --> Traces
  Worker --> CF
  Worker --> Queue --> APNs
  Worker --> Endpoint
  Endpoint --> RelayClient -->|"http://127.0.0.1:port"| Env
  Env --> Secrets
  Web -->|"environment token + DPoP<br/>HTTPS / WSS"| Endpoint
  Mobile -->|"environment token + DPoP<br/>HTTPS / WSS"| Endpoint
  Env -->|"environment bearer + signed activity proof"| Worker
        </pre>
      </section>

      <section class="panel" aria-label="Authentication matrix">
        <h2>Authentication and Transport Matrix</h2>
        <table>
          <thead>
            <tr>
              <th>Boundary</th>
              <th>Transport</th>
              <th>Authentication</th>
              <th>Purpose</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>Web or mobile -> relay link management</td>
              <td>HTTPS</td>
              <td>Clerk session-template bearer token</td>
              <td>Create a link challenge, submit an environment proof, list links, or unlink.</td>
            </tr>
            <tr>
              <td>CLI -> relay link management</td>
              <td>HTTPS</td>
              <td>Clerk OAuth access token obtained with PKCE</td>
              <td>Reconcile the desired headless cloud link when the server starts.</td>
            </tr>
            <tr>
              <td>Web or mobile -> relay protected client endpoints</td>
              <td>HTTPS</td>
              <td>Relay-issued DPoP token plus per-request DPoP proof</td>
              <td>
                Check environment status, request a remote connection, and register mobile devices.
              </td>
            </tr>
            <tr>
              <td>Relay -> managed environment endpoint</td>
              <td>HTTPS over the managed tunnel</td>
              <td>Short-lived relay-signed JWT request proof</td>
              <td>
                Request a signed health response or ask the local environment to mint a credential.
              </td>
            </tr>
            <tr>
              <td>Environment -> relay activity publication</td>
              <td>HTTPS</td>
              <td>Relay-issued environment bearer credential plus environment-signed JWT proof</td>
              <td>
                Publish redacted agent-activity state for push notifications and Live Activities.
              </td>
            </tr>
            <tr>
              <td>Remote client -> environment</td>
              <td>HTTPS and WSS over the managed tunnel</td>
              <td>Environment-issued access token bound to the client DPoP key</td>
              <td>Use the normal environment HTTP APIs and request a one-time WebSocket ticket.</td>
            </tr>
          </tbody>
        </table>
      </section>

      <section class="panel" aria-label="Credential ownership">
        <h2>Credential Ownership</h2>
        <table>
          <thead>
            <tr>
              <th>Credential</th>
              <th>Created by</th>
              <th>Stored by</th>
              <th>Use</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>Clerk session-template JWT</td>
              <td>Clerk</td>
              <td>Web or mobile client</td>
              <td>
                Authenticate cloud-user relay requests and bootstrap relay DPoP token exchange.
              </td>
            </tr>
            <tr>
              <td>CLI OAuth access and refresh token</td>
              <td>Clerk OAuth</td>
              <td>Local server secret store</td>
              <td>Authorize headless CLI link reconciliation.</td>
            </tr>
            <tr>
              <td>Environment Ed25519 key pair</td>
              <td>Local environment server</td>
              <td>Local server secret store</td>
              <td>
                Sign link proofs, health responses, mint responses, and activity publication proofs.
              </td>
            </tr>
            <tr>
              <td>Relay cloud-mint key pair</td>
              <td>Relay deployment</td>
              <td>Private key in relay Worker config; public key installed into the environment</td>
              <td>Sign relay-to-environment health and mint requests.</td>
            </tr>
            <tr>
              <td>Relay environment bearer credential</td>
              <td>Relay</td>
              <td>Hashed in relay Postgres; plaintext in local server secret store</td>
              <td>Authenticate environment-to-relay agent-activity publication.</td>
            </tr>
            <tr>
              <td>Relay DPoP access token</td>
              <td>Relay</td>
              <td>Remote client memory cache</td>
              <td>
                Authorize status, connect, and mobile registration endpoints with proof of
                possession.
              </td>
            </tr>
            <tr>
              <td>Environment bootstrap credential</td>
              <td>Local environment server</td>
              <td>Passed relay -> remote client</td>
              <td>One-time exchange at the environment <code>/oauth/token</code> endpoint.</td>
            </tr>
            <tr>
              <td>Environment access token</td>
              <td>Local environment server</td>
              <td>Remote client</td>
              <td>Authorize environment HTTP operations and WebSocket ticket issuance.</td>
            </tr>
            <tr>
              <td>WebSocket ticket</td>
              <td>Local environment server</td>
              <td>Remote client until consumed</td>
              <td>Short-lived one-time credential for the WSS upgrade.</td>
            </tr>
            <tr>
              <td>Relay client connector token</td>
              <td>Cloudflare tunnel API</td>
              <td>Local server secret store</td>
              <td>
                Start the local relay client. It is passed through <code>TUNNEL_TOKEN</code>, not a
                shell argument.
              </td>
            </tr>
          </tbody>
        </table>
      </section>

      <section class="grid" aria-label="Core flows">
        <article class="panel">
          <h2>Flow 1: Link From the Desktop Web UI</h2>
          <pre class="diagram mermaid">
sequenceDiagram
  participant U as Signed-in user
  participant C as Desktop web UI
  participant E as Local environment
  participant R as Relay Worker
  participant CF as Cloudflare APIs
  participant RC as Local relay client

  U->>C: Enable T3 Connect for a locally paired environment
  C->>E: Check relay client availability
  alt relay client is missing
    C->>U: Prompt before download and install
    U->>C: Confirm
    C->>E: Stream relay-client install RPC
    E-->>C: Progress stages
  end
  C->>R: POST /v1/client/environment-link-challenges (Clerk bearer)
  R-->>C: Short-lived challenge
  C->>E: POST /api/connect/link-proof (local relay:write bearer)
  E->>E: Authenticate, reject forwarded authority, get or create key pair, validate loopback origin
  E-->>C: Environment-signed link proof
  C->>R: POST /v1/client/environment-links (Clerk bearer + proof)
  R->>R: Verify challenge, proof, capabilities, nonce, and loopback origin
  R->>CF: Reconcile tunnel, ingress, and CNAME
  R->>R: Upsert user/environment link and issue environment bearer
  R-->>C: Managed endpoint, relay config, and connector token
  C->>E: POST /api/connect/relay-config (local relay:write bearer)
  E->>RC: Start relay client with TUNNEL_TOKEN
          </pre>
          <div class="callout">
            The local link-proof endpoint requires <code>relay:write</code>, rejects forwarded
            authority headers, and accepts only an exact loopback origin. Environment keypair
            persistence is atomic across concurrent link attempts.
          </div>
          <p>
            A locally paired mobile client uses the same relay challenge, local proof, relay link,
            and local relay-config endpoints. The desktop web UI is the surface that checks relay
            client availability and offers the managed install dialog.
          </p>
        </article>

        <article class="panel">
          <h2>Flow 2: Headless CLI Link</h2>
          <pre class="diagram mermaid">
sequenceDiagram
  participant U as Operator
  participant CLI as t3 connect CLI
  participant Clerk as Clerk OAuth
  participant S as Environment server on next start
  participant R as Relay Worker
  participant RC as Local relay client

  U->>CLI: t3 connect link
  CLI->>CLI: Resolve relay client
  alt relay client is missing
    CLI->>U: Confirm managed relay-client install
    U->>CLI: Confirm
    CLI->>CLI: Install with terminal progress updates
  end
  CLI->>Clerk: Browser PKCE authorization-code flow
  Clerk-->>CLI: OAuth access and refresh tokens
  CLI->>CLI: Persist desired cloud-link state
  U->>S: Start T3 environment server
  S->>R: Create challenge and submit local signed proof
  R-->>S: Managed endpoint config and connector token
  S->>RC: Start relay client
          </pre>
          <p>
            <code>t3 connect login</code> stores authorization without enabling exposure.
            <code>t3 connect unlink</code> disables exposure while retaining authorization.
            <code>t3 connect logout</code> also removes the stored CLI authorization.
          </p>
        </article>

        <article class="panel">
          <h2>Flow 3: Remote Connect Bootstrap</h2>
          <pre class="diagram mermaid">
sequenceDiagram
  participant C as Web or mobile client
  participant Clerk as Clerk
  participant R as Relay Worker
  participant E as Managed environment endpoint

  C->>Clerk: Get Clerk session-template JWT
  C->>R: POST /v1/client/dpop-token (Clerk JWT + DPoP proof)
  R-->>C: Relay DPoP access token
  C->>R: POST /v1/environments/:id/connect (relay DPoP)
  R->>E: POST /api/t3-connect/mint-credential (relay-signed proof)
  E->>E: Verify relay signer, linked user, scope, lifetime, cnf, and replay guards
  E-->>R: Bootstrap credential + environment-signed proof
  R->>R: Verify environment signature, nonce, endpoint, and DPoP binding
  R-->>C: Managed endpoint + bootstrap credential
  C->>E: POST /oauth/token (bootstrap credential + DPoP proof)
  E-->>C: Environment DPoP-bound access token
  C->>E: POST /api/auth/websocket-ticket
  E-->>C: One-time WebSocket ticket
  C->>E: WSS /ws with ticket
          </pre>
          <div class="callout">
            Relay-to-environment control requests disable redirects, use only a reconciled managed
            endpoint allocation, and require a signed environment response before the relay returns
            data to the client.
          </div>
        </article>

        <article class="panel">
          <h2>Flow 4: Agent Activity Notifications</h2>
          <pre class="diagram mermaid">
sequenceDiagram
  participant E as Local environment
  participant R as Relay Worker
  participant DB as Relay Postgres
  participant Q as APNs queue
  participant APNs as Apple Push Notification service
  participant M as Mobile app

  E->>E: Project publishable thread state and redact failure detail
  E->>R: POST /v1/environments/:environmentId/threads/:threadId/agent-activity
  Note over E,R: Environment bearer credential + environment-signed per-state proof
  R->>R: Verify credential, signature, scope, expiry, and nonce
  R->>DB: Store current activity row
  R->>Q: Enqueue push or Live Activity delivery jobs
  Q->>APNs: Deliver signed APNs request
  APNs-->>M: Push notification or Live Activity update
          </pre>
          <p>
            The local server publishes a deliberately narrow projection. Failed runs use a fixed
            redacted summary, and detail strings are capped before publication.
          </p>
        </article>
      </section>

      <section class="grid" aria-label="Managed endpoint lifecycle">
        <article class="panel half">
          <h2>Managed Endpoint Reconciliation</h2>
          <p>
            Managed endpoint resources are keyed by <code>(userId, environmentId)</code>. The relay
            reserves a stable hostname and tunnel name before provisioning, then checkpoints the
            tunnel ID, DNS record ID, and ready state in Postgres.
          </p>
          <div class="flow">
            <div class="step">
              <strong>1. Reserve deterministic allocation</strong>
              Hostname and tunnel name derive from relay stage, cloud user, and environment ID.
            </div>
            <div class="step">
              <strong>2. Reuse or create tunnel</strong>
              Existing named tunnels are reused. Tunnel ingress is rewritten to the validated
              loopback origin.
            </div>
            <div class="step">
              <strong>3. Reconcile DNS</strong>
              Existing CNAMEs are updated and duplicate records are removed. Create conflicts are
              recovered by listing and reconciling the winning record.
            </div>
            <div class="step">
              <strong>4. Mark ready</strong>
              Connect and status requests use only ready allocations whose hostname still matches
              the relay-managed namespace.
            </div>
          </div>
        </article>

        <article class="panel half">
          <h2>Unlink Cleanup</h2>
          <p>
            Relay unlink removes the user's managed endpoint allocation before revoking the
            user/environment link:
          </p>
          <ul>
            <li>delete the managed DNS record if present;</li>
            <li>delete the Cloudflare tunnel if present;</li>
            <li>remove the allocation row;</li>
            <li>revoke the user's environment link; and</li>
            <li>
              revoke the environment publication credential only after the final active link for
              that environment key disappears.
            </li>
          </ul>
          <p>
            Local unlink stops the relay client and removes the locally persisted relay URL, issuer,
            linked user, environment publication credential, cloud-mint public key, connector
            config, and agent-activity preference.
          </p>
        </article>
      </section>

      <section class="panel" aria-label="Cloudflare tunnel operational profile">
        <h2>Cloudflare Tunnel Operational Profile</h2>
        <p>
          Managed tunnels are private application backends, not general-purpose public hosting. The
          relay provisions one named Cloudflare tunnel and one DNS record per active
          <code>(userId, environmentId)</code> allocation.
        </p>
        <ul>
          <li>
            <strong>Lifecycle:</strong> the tunnel is created when an environment is linked, reused
            across retry-safe reconciliation, kept for the lifetime of that link, and deleted on
            unlink. If teardown fails, the allocation checkpoint remains so cleanup can be retried.
          </li>
          <li>
            <strong>Origin:</strong> tunnel ingress is restricted to the linked environment server's
            validated loopback HTTP origin. Arbitrary upstream hosts and raw TCP origins are
            rejected.
          </li>
          <li>
            <strong>Protocols:</strong> managed endpoints carry HTTPS request/response traffic and
            WSS connections only. Remote clients use the normal environment HTTP APIs and
            authenticated WebSocket RPC transport through the tunnel.
          </li>
          <li>
            <strong>Relay-generated traffic:</strong> the hosted relay sends sparse HTTPS health
            checks and credential-mint requests during status checks and remote connection
            bootstrap. It does not proxy steady-state remote sessions.
          </li>
          <li>
            <strong>Traffic shape:</strong> expected load is interactive and user-driven. Active
            remote sessions may keep WebSockets open and exchange terminal, agent, and UI updates;
            inactive linked environments should carry little or no tunnel traffic.
          </li>
          <li>
            <strong>Capacity planning:</strong> the project is pre-launch, so there is not yet a
            production bandwidth baseline. Tunnel count grows with active linked user/environment
            allocations, while bandwidth and concurrent WebSockets grow with active remote use.
          </li>
        </ul>
      </section>

      <section class="panel" aria-label="SSRF and tunnel hardening">
        <h2>SSRF and Tunnel Hardening</h2>
        <table>
          <thead>
            <tr>
              <th>Risk</th>
              <th>Implemented control</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>A client asks the relay to tunnel an arbitrary host.</td>
              <td>
                The environment and relay both accept managed tunnel origins only for loopback hosts
                and valid ports.
              </td>
            </tr>
            <tr>
              <td>A forwarded request tricks local origin validation.</td>
              <td>
                The local link-proof handler requires an exact loopback request URL and rejects
                forwarded host or protocol headers.
              </td>
            </tr>
            <tr>
              <td>A stored endpoint is replaced with an arbitrary external URL.</td>
              <td>
                Connect and status resolve a ready allocation from Postgres and require a hostname
                under the configured managed endpoint zone.
              </td>
            </tr>
            <tr>
              <td>A managed endpoint redirects relay egress elsewhere.</td>
              <td>
                Relay-to-environment status and mint requests set redirect handling to
                <code>manual</code>.
              </td>
            </tr>
            <tr>
              <td>A process behind the tunnel returns attacker-controlled data.</td>
              <td>
                The relay verifies environment-signed health and mint responses against the linked
                environment public key, expected nonce, and request binding.
              </td>
            </tr>
            <tr>
              <td>A stolen remote access token is replayed.</td>
              <td>
                Relay and environment access tokens are DPoP-bound; per-request proofs and replay
                guards are required.
              </td>
            </tr>
            <tr>
              <td>The relay client token leaks through process listings or shell parsing.</td>
              <td>
                The relay client is spawned without a shell and receives its connector token in
                <code>TUNNEL_TOKEN</code>.
              </td>
            </tr>
          </tbody>
        </table>
        <div class="callout warning">
          Managed tunnel hostnames live under the configured tunnel DNS zone. Serving them from a
          dedicated registrable domain with a Public Suffix List entry remains an operational
          isolation requirement before broad untrusted use.
        </div>
      </section>

      <section class="panel" aria-label="Relay HTTP API">
        <h2>Relay HTTP API</h2>
        <p>
          The relay publishes an OpenAPI document at <code>/openapi.json</code>, interactive API
          docs at <code>/docs</code>, and redirects <code>/</code> to the docs.
        </p>
        <table>
          <thead>
            <tr>
              <th>Endpoint</th>
              <th>Authentication</th>
              <th>Purpose</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td><code>GET /health</code></td>
              <td>None</td>
              <td>Relay health check.</td>
            </tr>
            <tr>
              <td><code>GET /.well-known/oauth-authorization-server</code></td>
              <td>None</td>
              <td>Relay OAuth token-exchange discovery metadata.</td>
            </tr>
            <tr>
              <td><code>GET /.well-known/oauth-protected-resource</code></td>
              <td>None</td>
              <td>Relay DPoP protected-resource discovery metadata.</td>
            </tr>
            <tr>
              <td><code>GET /v1/environments</code></td>
              <td>Clerk bearer</td>
              <td>List environments linked to the signed-in user.</td>
            </tr>
            <tr>
              <td><code>POST /v1/client/environment-link-challenges</code></td>
              <td>Clerk bearer</td>
              <td>Create a short-lived user-bound environment link challenge.</td>
            </tr>
            <tr>
              <td><code>POST /v1/client/environment-links</code></td>
              <td>Clerk bearer</td>
              <td>
                Verify a local environment proof, reconcile a managed endpoint, and upsert the user
                link.
              </td>
            </tr>
            <tr>
              <td><code>DELETE /v1/client/environment-links/:environmentId</code></td>
              <td>Clerk bearer</td>
              <td>Remove managed endpoint resources and revoke the user's link.</td>
            </tr>
            <tr>
              <td><code>POST /v1/client/dpop-token</code></td>
              <td>Clerk token in token-exchange payload plus DPoP proof</td>
              <td>Issue a relay DPoP access token for the requested supported scopes.</td>
            </tr>
            <tr>
              <td><code>POST /v1/environments/:environmentId/status</code></td>
              <td>Relay DPoP</td>
              <td>Request and validate a signed environment health response.</td>
            </tr>
            <tr>
              <td><code>POST /v1/environments/:environmentId/connect</code></td>
              <td>Relay DPoP</td>
              <td>Request and validate an environment bootstrap credential.</td>
            </tr>
            <tr>
              <td><code>POST /v1/mobile/devices</code></td>
              <td>Relay DPoP</td>
              <td>Register or update a mobile device for notifications.</td>
            </tr>
            <tr>
              <td><code>POST /v1/mobile/live-activities</code></td>
              <td>Relay DPoP</td>
              <td>Register a Live Activity push token.</td>
            </tr>
            <tr>
              <td><code>DELETE /v1/mobile/devices/:deviceId</code></td>
              <td>Relay DPoP</td>
              <td>Unregister a mobile device.</td>
            </tr>
            <tr>
              <td>
                <code>POST /v1/environments/:environmentId/threads/:threadId/agent-activity</code>
              </td>
              <td>Environment bearer plus signed publish proof</td>
              <td>Publish redacted current agent activity for notification delivery.</td>
            </tr>
          </tbody>
        </table>
      </section>

      <section class="panel" aria-label="Environment HTTP API">
        <h2>Environment Cloud HTTP API</h2>
        <table>
          <thead>
            <tr>
              <th>Endpoint</th>
              <th>Authentication</th>
              <th>Purpose</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td><code>POST /api/connect/link-proof</code></td>
              <td>Local environment token with <code>relay:write</code></td>
              <td>Validate local origin and sign an environment link proof.</td>
            </tr>
            <tr>
              <td><code>POST /api/connect/relay-config</code></td>
              <td>Local environment token with <code>relay:write</code></td>
              <td>Persist linked relay configuration and start the relay client.</td>
            </tr>
            <tr>
              <td><code>GET /api/connect/link-state</code></td>
              <td>Local environment token with <code>relay:read</code></td>
              <td>Read the environment's current T3 Connect link state.</td>
            </tr>
            <tr>
              <td><code>POST /api/connect/preferences</code></td>
              <td>Local environment token with <code>relay:write</code></td>
              <td>Enable or disable agent-activity publication.</td>
            </tr>
            <tr>
              <td><code>POST /api/connect/unlink</code></td>
              <td>Local environment token with <code>relay:write</code></td>
              <td>Stop the relay client and clear local T3 Connect configuration.</td>
            </tr>
            <tr>
              <td><code>POST /api/t3-connect/health</code></td>
              <td>Relay-signed proof</td>
              <td>Return a signed environment health response.</td>
            </tr>
            <tr>
              <td><code>POST /api/t3-connect/mint-credential</code></td>
              <td>Relay-signed proof</td>
              <td>Mint a DPoP-bound one-time bootstrap credential for a remote client.</td>
            </tr>
            <tr>
              <td><code>POST /oauth/token</code></td>
              <td>Bootstrap credential plus DPoP proof</td>
              <td>Exchange a bootstrap credential for an environment access token.</td>
            </tr>
            <tr>
              <td><code>POST /api/auth/websocket-ticket</code></td>
              <td>Environment access token</td>
              <td>Issue a one-time ticket for the WSS upgrade.</td>
            </tr>
          </tbody>
        </table>
      </section>

      <section class="grid" aria-label="Runtime and infrastructure">
        <article class="panel half">
          <h2>Relay Client Installation</h2>
          <p>
            Desktop web UI availability checks and installs are local WebSocket RPC methods:
            <code>cloud.getRelayClientStatus</code> and streaming
            <code>cloud.installRelayClient</code>. The install stream emits the current stage:
            checking, waiting for lock, downloading, verifying, installing, validating, and
            activating.
          </p>
          <p>
            The web UI asks for confirmation before installation and displays a custom progress
            dialog. The CLI invokes the same local relay-client service directly and reports the
            same progress stages in the terminal.
          </p>
        </article>

        <article class="panel half">
          <h2>Relay Infrastructure</h2>
          <ul>
            <li>Cloudflare Worker for the hosted relay HTTP API.</li>
            <li>PlanetScale Postgres database named <code>t3coderelay</code>.</li>
            <li>
              Production uses the shared database; non-production stages use database branches.
            </li>
            <li>
              Cloudflare Hyperdrive with caching disabled and a constrained origin connection limit.
            </li>
            <li>Cloudflare tunnel and DNS bindings for managed endpoint reconciliation.</li>
            <li>Cloudflare APNs delivery queue plus dead-letter queue.</li>
            <li>A five-minute cron job that prunes expired DPoP replay rows.</li>
            <li>Axiom OTLP trace dataset, scoped ingest token, and recent-spans view per stage.</li>
          </ul>
        </article>
      </section>

      <section class="panel" aria-label="Deployment configuration">
        <h2>Deployment Configuration</h2>
        <table>
          <thead>
            <tr>
              <th>Boundary</th>
              <th>Configuration</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>Relay infrastructure</td>
              <td>
                <code>RELAY_API_ZONE_NAME</code>, <code>RELAY_TUNNEL_ZONE_NAME</code>, optional
                <code>RELAY_DOMAIN</code>, <code>CLERK_PUBLISHABLE_KEY</code>,
                <code>CLERK_SECRET_KEY</code>, <code>CLERK_JWT_AUDIENCE</code>, and APNs
                credentials.
              </td>
            </tr>
            <tr>
              <td>Source-built desktop/server cloud features</td>
              <td>
                Optional <code>T3CODE_RELAY_URL</code>, <code>T3CODE_CLERK_PUBLISHABLE_KEY</code>,
                and <code>T3CODE_CLERK_CLI_OAUTH_CLIENT_ID</code>. Release builds inject public
                values at build time.
              </td>
            </tr>
            <tr>
              <td>Web and mobile cloud clients</td>
              <td>
                Public Clerk publishable key, Clerk JWT template name, and relay URL. Relay URLs
                must normalize to an absolute HTTPS origin without credentials, query, fragment, or
                non-root path.
              </td>
            </tr>
          </tbody>
        </table>
      </section>

      <section class="panel" aria-label="Implementation checklist">
        <h2>Implementation Checklist</h2>
        <ul>
          <li>
            Keep the relay cloud-mint private key hosted-only; install only its public key into
            environments.
          </li>
          <li>
            Keep environment signing private keys local and persist keypair creation atomically.
          </li>
          <li>
            Require a local <code>relay:write</code> session before linking or changing relay
            config.
          </li>
          <li>Validate relay URLs as secure absolute HTTPS origins before sending credentials.</li>
          <li>Require loopback-only tunnel origins on both sides of the link-proof boundary.</li>
          <li>
            Resolve managed endpoint egress from ready allocation rows, not client-supplied URLs.
          </li>
          <li>Disable redirects on relay-to-environment requests.</li>
          <li>Validate environment-signed response proofs before consuming tunneled responses.</li>
          <li>Keep tunnel and DNS provisioning retry-safe and deprovision them on unlink.</li>
          <li>
            Revoke shared environment publication credentials only after the final active link
            disappears.
          </li>
          <li>Redact and cap local agent failure details before publishing them externally.</li>
        </ul>
      </section>

      <section class="panel" aria-label="Standards references">
        <h2>Standards References</h2>
        <ul class="source-list">
          <li>
            <a href="https://www.rfc-editor.org/rfc/rfc8252">RFC 8252</a>: browser-based OAuth for
            native apps, used by the CLI PKCE authorization flow.
          </li>
          <li>
            <a href="https://www.rfc-editor.org/rfc/rfc8693">RFC 8693</a>: OAuth token exchange,
            used for Clerk-token to relay-DPoP-token exchange.
          </li>
          <li>
            <a href="https://www.rfc-editor.org/rfc/rfc9449">RFC 9449</a>: DPoP proof of possession,
            used for relay and environment access tokens.
          </li>
        </ul>
      </section>
    </main>
    <script type="module">
      import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs";

      mermaid.initialize({
        startOnLoad: false,
        securityLevel: "strict",
        theme: "base",
        themeVariables: {
          fontFamily: 'ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
          primaryColor: "#eef4ff",
          primaryBorderColor: "#1457d9",
          primaryTextColor: "#171717",
          lineColor: "#62646b",
          signalColor: "#171717",
          signalTextColor: "#171717",
          noteBkgColor: "#fff6e6",
          noteTextColor: "#171717",
          actorBkg: "#fbfbf8",
          actorBorder: "#62646b",
          actorTextColor: "#171717",
        },
        flowchart: {
          htmlLabels: true,
          curve: "basis",
          padding: 18,
        },
        sequence: {
          showSequenceNumbers: true,
          mirrorActors: false,
          rightAngles: false,
        },
      });

      await mermaid.run({ querySelector: ".diagram.mermaid" });

      for (const svg of document.querySelectorAll(".diagram.mermaid svg")) {
        const viewBox = svg.getAttribute("viewBox");
        const width = viewBox?.split(/\s+/).map(Number)[2];
        if (Number.isFinite(width) && width > 0) {
          svg.style.setProperty("width", `${Math.ceil(width)}px`, "important");
          svg.style.setProperty("max-width", "none", "important");
        }
      }
    </script>
  </body>
</html>

```
