authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-06-13 21:57:32-07:00
committergravatar for me@theo.liTheo Browne <me@theo.li> 2026-06-13 22:18:37-07:00
log3a0623f1cd7864aa21b49bdac03e57da876ed6ba
tree3c2ce67a9a3d2803a5380ffcae2d648618f1e2db
parentcd91ec75f3558e457693b502e7a70201f3cf6d03

rm test artifacts


2 files changed, 0 insertions(+), 592 deletions(-)

docs/cloud/t3-code-connect-auth-flow-3-page.html deleted-592
...@@ -1,592 +0,0 @@
1<!doctype html>
2<html lang="en">
3 <head>
4 <meta charset="utf-8" />
5 <meta name="viewport" content="width=device-width, initial-scale=1" />
6 <title>T3 Connect Architecture Brief</title>
7 <style>
8 :root {
9 --ink: #171717;
10 --muted: #62646b;
11 --line: #d8d8dd;
12 --paper: #f5f5f2;
13 --blue: #1457d9;
14 --green: #1d7d4d;
15 --amber: #a65f00;
16 }
17 * {
18 box-sizing: border-box;
19 }
20 @page {
21 size: Letter;
22 margin: 0;
23 }
24 body {
25 margin: 0;
26 color: var(--ink);
27 background: #ddd;
28 font-family:
29 ui-sans-serif,
30 -apple-system,
31 BlinkMacSystemFont,
32 "Segoe UI",
33 sans-serif;
34 line-height: 1.34;
35 }
36 .page {
37 position: relative;
38 width: 8.5in;
39 height: 11in;
40 margin: 20px auto;
41 padding: 0.47in 0.52in 0.42in;
42 overflow: hidden;
43 background:
44 linear-gradient(90deg, rgba(0, 0, 0, 0.028) 1px, transparent 1px),
45 linear-gradient(rgba(0, 0, 0, 0.028) 1px, transparent 1px), var(--paper);
46 background-size: 25px 25px;
47 break-after: page;
48 }
49 .page:last-child {
50 break-after: auto;
51 }
52 .eyebrow {
53 color: var(--blue);
54 font-size: 9px;
55 font-weight: 800;
56 letter-spacing: 0.1em;
57 text-transform: uppercase;
58 }
59 h1 {
60 max-width: 6.9in;
61 margin: 7px 0 10px;
62 font-size: 35px;
63 line-height: 0.98;
64 }
65 h2 {
66 margin: 0 0 8px;
67 font-size: 19px;
68 line-height: 1.08;
69 }
70 h3 {
71 margin: 0 0 4px;
72 font-size: 12px;
73 }
74 p {
75 margin: 0 0 7px;
76 }
77 ul {
78 margin: 5px 0 0;
79 padding-left: 17px;
80 }
81 li + li {
82 margin-top: 3px;
83 }
84 code {
85 border-radius: 3px;
86 background: #ecece8;
87 padding: 1px 3px;
88 font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
89 font-size: 0.9em;
90 }
91 .lede {
92 max-width: 7.1in;
93 color: var(--muted);
94 font-size: 12px;
95 }
96 .rule {
97 height: 2px;
98 margin: 14px 0;
99 background: var(--ink);
100 }
101 .grid {
102 display: grid;
103 grid-template-columns: repeat(12, 1fr);
104 gap: 10px;
105 }
106 .panel {
107 grid-column: span 12;
108 border: 1px solid var(--line);
109 border-radius: 7px;
110 background: rgba(255, 255, 255, 0.94);
111 padding: 12px;
112 font-size: 10px;
113 }
114 .half {
115 grid-column: span 6;
116 }
117 .third {
118 grid-column: span 4;
119 }
120 .callout {
121 margin-top: 8px;
122 border-left: 4px solid var(--blue);
123 background: #eef4ff;
124 padding: 8px 9px;
125 font-size: 10px;
126 }
127 .warning {
128 border-left-color: var(--amber);
129 background: #fff6e6;
130 }
131 .topology {
132 display: grid;
133 grid-template-columns: 1.1fr 34px 1.1fr 34px 1.1fr;
134 align-items: center;
135 gap: 5px;
136 margin-top: 8px;
137 }
138 .node {
139 min-height: 58px;
140 border: 1px solid var(--line);
141 border-top: 4px solid var(--blue);
142 border-radius: 6px;
143 background: white;
144 padding: 8px;
145 text-align: center;
146 font-size: 9px;
147 }
148 .node.green {
149 border-top-color: var(--green);
150 }
151 .arrow {
152 color: var(--muted);
153 text-align: center;
154 font-size: 22px;
155 }
156 .flow {
157 display: grid;
158 grid-template-columns: repeat(4, 1fr);
159 gap: 7px;
160 margin-top: 8px;
161 }
162 .step {
163 position: relative;
164 min-height: 80px;
165 border: 1px solid var(--line);
166 border-left: 4px solid var(--green);
167 border-radius: 6px;
168 background: white;
169 padding: 8px;
170 font-size: 9px;
171 }
172 .step b {
173 display: block;
174 margin-bottom: 3px;
175 font-size: 10px;
176 }
177 table {
178 width: 100%;
179 border-collapse: collapse;
180 font-size: 8.7px;
181 }
182 th,
183 td {
184 border-bottom: 1px solid var(--line);
185 padding: 5px 6px;
186 text-align: left;
187 vertical-align: top;
188 }
189 th {
190 color: var(--muted);
191 font-size: 8px;
192 letter-spacing: 0.05em;
193 text-transform: uppercase;
194 }
195 .footer {
196 position: absolute;
197 right: 0.52in;
198 bottom: 0.18in;
199 color: var(--muted);
200 font-size: 8px;
201 }
202 @media print {
203 body {
204 background: none;
205 }
206 .page {
207 margin: 0;
208 }
209 }
210 </style>
211 </head>
212 <body>
213 <section class="page">
214 <div class="eyebrow">Architecture brief · page 1 of 3</div>
215 <h1>T3 Connect Control Plane and Managed Endpoint Flow</h1>
216 <p class="lede">
217 T3 Connect links a locally authorized T3 environment to a signed-in cloud user, provisions a
218 managed HTTPS/WSS endpoint, and brokers proof-bound remote connections. The environment
219 remains the access authority; the relay coordinates identity, endpoint lifecycle, and
220 notifications.
221 </p>
222 <div class="rule"></div>
223
224 <div class="grid">
225 <article class="panel half">
226 <h2>Security Invariant</h2>
227 <p>Cloud identity alone is not an environment login. Remote access requires:</p>
228 <ul>
229 <li>a Clerk-authenticated T3 Connect user;</li>
230 <li>an active user/environment relay link;</li>
231 <li>a DPoP private key held by the remote client;</li>
232 <li>a relay-signed mint request accepted locally; and</li>
233 <li>an environment token bound to the client's DPoP key.</li>
234 </ul>
235 <div class="callout">
236 The relay cannot mint an environment access token by itself. The local environment
237 issues the bootstrap credential and final access token.
238 </div>
239 </article>
240 <article class="panel half">
241 <h2>Trust Boundaries</h2>
242 <ul>
243 <li><b>Clerk:</b> user identity and OAuth/PKCE.</li>
244 <li><b>Relay Worker:</b> links, endpoint allocations, proofs, and notifications.</li>
245 <li><b>Environment:</b> local sessions, signing keys, and access tokens.</li>
246 <li><b>Relay client:</b> exposes only the validated loopback HTTP server.</li>
247 <li><b>Remote client:</b> retains the DPoP private key and environment token.</li>
248 </ul>
249 <div class="callout warning">
250 The relay remains a trusted mint broker because it holds the cloud-mint signing key.
251 DPoP limits credential reuse but does not neutralize compromise of that authority.
252 </div>
253 </article>
254
255 <article class="panel">
256 <h2>Current Topology</h2>
257 <div class="topology">
258 <div class="node">
259 <h3>Clients</h3>
260 Desktop web UI<br />Mobile app<br />Headless CLI<br /><br />
261 <b>Clerk bearer / relay DPoP</b>
262 </div>
263 <div class="arrow">→</div>
264 <div class="node">
265 <h3>T3 Code Relay</h3>
266 Cloudflare Worker<br />Hyperdrive + Postgres<br />Tunnel/DNS APIs<br />APNs queue
267 </div>
268 <div class="arrow">→</div>
269 <div class="node green">
270 <h3>Linked Environment</h3>
271 Managed HTTPS/WSS endpoint<br />Relay client<br />Loopback server<br />Local secrets
272 </div>
273 </div>
274 <div class="callout">
275 Steady-state HTTP and WebSocket traffic goes directly from the remote client through the
276 managed endpoint. The relay handles sparse health and bootstrap requests, not the active
277 session data path.
278 </div>
279 </article>
280
281 <article class="panel">
282 <h2>Authentication Boundaries</h2>
283 <table>
284 <thead>
285 <tr>
286 <th>Boundary</th>
287 <th>Authentication</th>
288 <th>Purpose</th>
289 </tr>
290 </thead>
291 <tbody>
292 <tr>
293 <td>Client → relay link management</td>
294 <td>Clerk bearer / CLI OAuth</td>
295 <td>Create, list, or remove links.</td>
296 </tr>
297 <tr>
298 <td>Client → protected relay APIs</td>
299 <td>Relay DPoP token + proof</td>
300 <td>Status, connect, and mobile registration.</td>
301 </tr>
302 <tr>
303 <td>Relay → environment</td>
304 <td>Short-lived relay-signed JWT</td>
305 <td>Signed health and credential-mint requests.</td>
306 </tr>
307 <tr>
308 <td>Client → environment</td>
309 <td>Environment token + DPoP</td>
310 <td>Normal HTTPS APIs and WSS ticket issuance.</td>
311 </tr>
312 <tr>
313 <td>Environment → relay</td>
314 <td>Environment bearer + signed proof</td>
315 <td>Publish redacted agent activity.</td>
316 </tr>
317 </tbody>
318 </table>
319 </article>
320 </div>
321 <div class="footer">T3 Connect Architecture Brief · 1</div>
322 </section>
323
324 <section class="page">
325 <div class="eyebrow">Core workflows · page 2 of 3</div>
326 <h1>Link, Bootstrap, and Operate</h1>
327 <p class="lede">
328 Every workflow preserves local authority while making cloud coordination retry-safe and
329 suitable for desktop, mobile, and headless use.
330 </p>
331 <div class="rule"></div>
332
333 <div class="grid">
334 <article class="panel">
335 <h2>1. Link a Local Environment</h2>
336 <div class="flow">
337 <div class="step">
338 <b>Authenticate</b>Desktop/mobile uses a Clerk bearer. CLI uses browser PKCE and
339 persists desired link state.
340 </div>
341 <div class="step">
342 <b>Prove locally</b>Relay issues a short-lived challenge. The local environment
343 validates loopback origin and signs it.
344 </div>
345 <div class="step">
346 <b>Reconcile</b>Relay verifies proof and capabilities, then creates or reuses the
347 tunnel, ingress, and CNAME.
348 </div>
349 <div class="step">
350 <b>Activate</b>Relay returns endpoint config and connector token. Environment persists
351 config and starts the relay client.
352 </div>
353 </div>
354 <div class="callout">
355 The local proof endpoint requires <code>relay:write</code>, rejects forwarded authority
356 headers, and atomically persists the environment key pair.
357 </div>
358 </article>
359
360 <article class="panel">
361 <h2>2. Remote Connection Bootstrap</h2>
362 <div class="flow">
363 <div class="step">
364 <b>Proof key</b>Client creates a DPoP key and exchanges its Clerk JWT for a relay DPoP
365 access token.
366 </div>
367 <div class="step">
368 <b>Mint request</b>Client calls connect. Relay sends an audience-bound, short-lived
369 signed proof to the managed endpoint.
370 </div>
371 <div class="step">
372 <b>Local issue</b>Environment validates user, scope, lifetime, nonce, and DPoP
373 thumbprint, then returns a signed bootstrap credential.
374 </div>
375 <div class="step">
376 <b>Direct session</b>Client redeems locally for an environment token, gets a one-time
377 WSS ticket, and opens the WebSocket.
378 </div>
379 </div>
380 <div class="callout">
381 The relay validates the environment response signature, nonce, endpoint, and DPoP
382 binding before returning bootstrap data to the client.
383 </div>
384 </article>
385
386 <article class="panel half">
387 <h2>Managed Endpoint Lifecycle</h2>
388 <ol>
389 <li>
390 Reserve deterministic hostname and tunnel name for
391 <code>(userId, environmentId)</code>.
392 </li>
393 <li>
394 Reuse or create the named tunnel; rewrite ingress to the validated loopback origin.
395 </li>
396 <li>
397 Reconcile CNAME records and remove duplicates; recover safely from create conflicts.
398 </li>
399 <li>Mark ready only after resource IDs and namespace checks are persisted.</li>
400 </ol>
401 </article>
402 <article class="panel half">
403 <h2>Unlink Cleanup</h2>
404 <ul>
405 <li>Delete managed DNS and tunnel resources.</li>
406 <li>Remove the allocation and revoke the user link.</li>
407 <li>Revoke publication credentials after the final active link disappears.</li>
408 <li>Stop the local relay client and clear persisted relay configuration.</li>
409 <li>Retain checkpoints when teardown fails so cleanup can be retried.</li>
410 </ul>
411 </article>
412
413 <article class="panel">
414 <h2>3. Agent Activity Notifications</h2>
415 <div class="flow">
416 <div class="step">
417 <b>Project</b>Environment creates a narrow publishable thread state and redacts/caps
418 failure details.
419 </div>
420 <div class="step">
421 <b>Sign</b>Environment posts with its bearer credential and a per-state signed proof.
422 </div>
423 <div class="step">
424 <b>Persist</b>Relay checks credential, signature, scope, expiry, and nonce, then
425 stores current state.
426 </div>
427 <div class="step">
428 <b>Deliver</b>Queue workers send push notifications or Live Activity updates through
429 APNs.
430 </div>
431 </div>
432 </article>
433 </div>
434 <div class="footer">T3 Connect Architecture Brief · 2</div>
435 </section>
436
437 <section class="page">
438 <div class="eyebrow">Controls and operations · page 3 of 3</div>
439 <h1>Hardening and Deployment Contract</h1>
440 <p class="lede">
441 The design constrains tunnel origins, proof audiences, egress destinations, redirects,
442 credential exposure, and teardown behavior.
443 </p>
444 <div class="rule"></div>
445
446 <div class="grid">
447 <article class="panel">
448 <h2>SSRF and Tunnel Controls</h2>
449 <table>
450 <thead>
451 <tr>
452 <th>Risk</th>
453 <th>Implemented control</th>
454 </tr>
455 </thead>
456 <tbody>
457 <tr>
458 <td>Arbitrary tunnel upstream</td>
459 <td>Both sides accept managed origins only for loopback hosts and valid ports.</td>
460 </tr>
461 <tr>
462 <td>Forwarded-origin confusion</td>
463 <td>
464 Link proof requires the exact loopback URL and rejects forwarded host/protocol
465 headers.
466 </td>
467 </tr>
468 <tr>
469 <td>Stored endpoint replacement</td>
470 <td>
471 Status/connect resolve ready allocations from Postgres and require the managed DNS
472 namespace.
473 </td>
474 </tr>
475 <tr>
476 <td>Redirected relay egress</td>
477 <td>Relay health and mint requests use manual redirect handling.</td>
478 </tr>
479 <tr>
480 <td>Impersonated tunnel backend</td>
481 <td>Relay verifies signed environment responses, nonce, and request binding.</td>
482 </tr>
483 <tr>
484 <td>Stolen access token replay</td>
485 <td>Relay and environment tokens require DPoP proofs and replay guards.</td>
486 </tr>
487 <tr>
488 <td>Connector token exposure</td>
489 <td>
490 Relay client is spawned without a shell and receives the token in
491 <code>TUNNEL_TOKEN</code>.
492 </td>
493 </tr>
494 </tbody>
495 </table>
496 </article>
497
498 <article class="panel half">
499 <h2>Credential Ownership</h2>
500 <ul>
501 <li>Environment Ed25519 private key stays local.</li>
502 <li>
503 Cloud-mint private key stays in hosted relay config; only its public key is installed
504 locally.
505 </li>
506 <li>
507 Relay environment bearer is hashed in Postgres and stored plaintext only locally.
508 </li>
509 <li>Remote DPoP private keys and environment access tokens remain client-side.</li>
510 <li>WebSocket tickets are short-lived and one-time.</li>
511 </ul>
512 </article>
513 <article class="panel half">
514 <h2>Operational Profile</h2>
515 <ul>
516 <li>One named tunnel and DNS record per active user/environment allocation.</li>
517 <li>HTTPS request/response and WSS only; no arbitrary TCP exposure.</li>
518 <li>Relay traffic is limited to health and bootstrap control calls.</li>
519 <li>
520 Active sessions are interactive and WebSocket-heavy; inactive links are nearly idle.
521 </li>
522 <li>
523 Dedicated registrable tunnel domain and Public Suffix List entry are required before
524 broad untrusted use.
525 </li>
526 </ul>
527 </article>
528
529 <article class="panel">
530 <h2>Deployment and Runtime</h2>
531 <table>
532 <thead>
533 <tr>
534 <th>Layer</th>
535 <th>Contract</th>
536 </tr>
537 </thead>
538 <tbody>
539 <tr>
540 <td>Relay</td>
541 <td>
542 Cloudflare Worker, tunnel/DNS bindings, Hyperdrive, PlanetScale Postgres, APNs
543 queue + DLQ, replay-row pruning cron, and Axiom OTLP traces.
544 </td>
545 </tr>
546 <tr>
547 <td>Environment</td>
548 <td>
549 Loopback server, atomic secret store, relay-client lifecycle, signed health/mint
550 responses, OAuth exchange, and WebSocket tickets.
551 </td>
552 </tr>
553 <tr>
554 <td>Clients</td>
555 <td>
556 Secure relay URL, Clerk configuration, DPoP key management, environment token
557 storage, and direct managed-endpoint traffic.
558 </td>
559 </tr>
560 </tbody>
561 </table>
562 </article>
563
564 <article class="panel">
565 <h2>Release Gate</h2>
566 <div class="grid">
567 <div class="third">
568 <h3>Identity</h3>
569 Keep private signing keys in their owning trust domain. Validate issuer, audience,
570 scope, expiry, nonce, and proof-key binding.
571 </div>
572 <div class="third">
573 <h3>Network</h3>
574 Permit loopback tunnel origins only. Resolve relay egress from ready allocations and
575 disable redirects.
576 </div>
577 <div class="third">
578 <h3>Lifecycle</h3>
579 Make provisioning idempotent, preserve failed-cleanup checkpoints, and revoke shared
580 credentials only after the final link disappears.
581 </div>
582 </div>
583 <div class="callout warning">
584 Standards basis: RFC 8252 for native-app OAuth, RFC 8693 for token exchange, and RFC
585 9449 for DPoP proof of possession.
586 </div>
587 </article>
588 </div>
589 <div class="footer">T3 Connect Architecture Brief · 3</div>
590 </section>
591 </body>
592</html>
docs/cloud/t3-code-connect-auth-flow.pdf deleted
Binary files a/docs/cloud/t3-code-connect-auth-flow.pdf and /dev/null differ