Security Invariant
A cloud identity is not an environment login. Remote access requires all of the
following:
- a Clerk-authenticated T3 Connect user;
- an active relay link for that user and environment;
- a DPoP proof key held by the remote client;
- a relay-signed mint request accepted by the linked local environment; and
- an environment-issued credential bound to the remote client's DPoP thumbprint.
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.
During an honest connection flow, the relay cannot act as the remote client:
-
Normal environment API traffic goes directly from the remote client through the
managed endpoint. The relay does not receive the resulting environment access token.
-
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.
-
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.
-
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.
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.
Product Boundaries
The generic local connector is called the relay client. The current
implementation layer uses cloudflared, but that is an internal transport
detail rather than the product contract.
-
The relay Worker owns cloud links, managed endpoint allocations, and notifications.
-
The environment server owns local sessions, environment keys, and access tokens.
- The relay client exposes only the environment's loopback HTTP server.
-
Web and mobile clients connect directly to the managed environment endpoint after
bootstrap.
Flow 1: Link From the Desktop Web UI
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
The local link-proof endpoint requires relay:write, rejects forwarded
authority headers, and accepts only an exact loopback origin. Environment keypair
persistence is atomic across concurrent link attempts.
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.
Flow 2: Headless CLI Link
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
t3 connect login stores authorization without enabling exposure.
t3 connect unlink disables exposure while retaining authorization.
t3 connect logout also removes the stored CLI authorization.
Flow 3: Remote Connect Bootstrap
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
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.
Flow 4: Agent Activity Notifications
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
The local server publishes a deliberately narrow projection. Failed runs use a fixed
redacted summary, and detail strings are capped before publication.
Managed Endpoint Reconciliation
Managed endpoint resources are keyed by (userId, environmentId). The relay
reserves a stable hostname and tunnel name before provisioning, then checkpoints the
tunnel ID, DNS record ID, and ready state in Postgres.
1. Reserve deterministic allocation
Hostname and tunnel name derive from relay stage, cloud user, and environment ID.
2. Reuse or create tunnel
Existing named tunnels are reused. Tunnel ingress is rewritten to the validated
loopback origin.
3. Reconcile DNS
Existing CNAMEs are updated and duplicate records are removed. Create conflicts are
recovered by listing and reconciling the winning record.
4. Mark ready
Connect and status requests use only ready allocations whose hostname still matches
the relay-managed namespace.
Unlink Cleanup
Relay unlink removes the user's managed endpoint allocation before revoking the
user/environment link:
- delete the managed DNS record if present;
- delete the Cloudflare tunnel if present;
- remove the allocation row;
- revoke the user's environment link; and
-
revoke the environment publication credential only after the final active link for
that environment key disappears.
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.