---
title: "T3 Connect"
type: concept
tags: [remote, architecture, advanced, well-established]
created: 2026-08-06
updated: 2026-08-06
sources: ["raw/github_doc-docs-internals-t3-connect-md.md", "raw/github_doc-docs-internals-connection-runtime-md.md"]
confidence: high
t3code_version: "0.0.32-nightly (2026-08-05)"
---

## Definition

T3 Connect is T3 Code's managed relay/tunnel solution for remote access — the mechanism behind
`RelayConnectionTarget` (see [[concepts/remote-access]]). It uses a single Clerk application for
web, desktop, and mobile authentication, and answers the case where the host is behind NAT,
inbound ports are unavailable, or a mobile client needs to reach a desktop-hosted environment
without router or firewall changes.

## How It Works

### Authentication

The relay verifies two kinds of bearer credential: template JWTs generated from the `t3-relay`
Clerk JWT template with the shared `t3-code-relay` audience, and Clerk OAuth tokens issued to the
CLI. `verifyRelayClientBearerToken` tries the template/session path first and falls back to OAuth
verification, so the CLI's OAuth credential works without needing a JWT template.

T3 Connect is disabled in a fresh clone; enabling it for source builds requires a repository-root
`.env`/`.env.local` with `T3CODE_CLERK_PUBLISHABLE_KEY`, `T3CODE_CLERK_JWT_TEMPLATE`,
`T3CODE_CLERK_CLI_OAUTH_CLIENT_ID`, and `T3CODE_RELAY_URL`. These are public identifiers, not
secrets, and are statically injected into client builds; a built artifact needs no environment
file at runtime. When client-facing public values are absent, cloud UI is omitted, but the
`t3 connect` command group always registers — it reports the missing configuration rather than
silently disappearing from help.

### The `t3 connect` command group

```sh
t3 connect            # default: onboarding
t3 connect login
t3 connect link       # --publish-only
t3 connect status     # --json
t3 connect publish    # --disable
t3 connect unlink
t3 connect logout
```

`t3 serve` is a separate top-level command, not a connect subcommand (see
[[concepts/remote-access]]). `t3 connect login` opens the Clerk authorization flow and stores the
CLI credential without enabling cloud exposure. `t3 connect link` installs the pinned managed
`cloudflared` binary when needed, authorizes when needed, and records durable intent to expose the
environment — it works without a running T3 server; the next `t3 serve`/`t3 start` reconciles the
relay link and launches the managed tunnel. `t3 connect unlink` records disabled intent
immediately, stops a reachable running connector, and attempts to revoke the relay-side
environment record, but keeps the stored CLI authorization so `link` can re-enable exposure
without another browser flow. `t3 connect logout` does the same cleanup and also removes the
stored CLI authorization.

The headless CLI OAuth flow uses a separate Clerk OAuth application, configured as a **public**
client with PKCE (no client secret stored by the CLI), with allowed redirect URIs for both a
loopback listener (`http://127.0.0.1:34338/callback`) and a hosted out-of-band flow
(`https://app.t3.codes/connect/callback`, or `$T3CODE_HOSTED_APP_URL/connect/callback` when
`T3CODE_HOSTED_APP_URL` is customized). The relay is not involved in the OAuth handshake itself —
it only validates the resulting Clerk bearer token when the CLI manages an environment link. When
`--headless` is passed, or SSH is detected via `SSH_CONNECTION`/`SSH_TTY`, `authorizeCli`
automatically selects the out-of-band flow (prints a hosted authorization URL, accepts a pasted
code) instead of the loopback listener, so port forwarding is optional rather than required.

### Relay traffic path

From the client's perspective, a relay-tunneled connection is still an ordinary WebSocket
connection — the route is simply mediated. The relay Worker only brokers credentials and a managed
endpoint; application traffic then flows over the provisioned Cloudflare tunnel hostname for the
life of the connection, not through the relay Worker itself.

### Client-side handling of relay connections

On the client, T3 Connect's relay path is one of the four connection target kinds resolved by the
shared connection runtime (`ConnectionResolver`, `ConnectionDriver`) described in
[[concepts/architecture]]. Two relay-specific behaviors are called out as required test coverage
for that runtime: **relay token reuse and refresh**, and **progressive relay discovery**. Credential
changes interrupt an in-flight connection establishment only for relay targets specifically,
because a new credential changes what is actually being established — unlike primary, bearer, or
SSH targets, where a credential change does not interrupt establishment the same way.

### Background service interaction

The background service ([[concepts/background-service]]) has an independent lifecycle from T3
Connect: Connect setup may offer to install the service during onboarding, but `t3 connect logout`
leaves the service running. Manage the service separately with `t3 service status`, `install`,
`update`, and `uninstall`.

## Key Parameters

- **Shared audience**: `t3-code-relay` (Clerk JWT template name `t3-relay`).
- **Config precedence**: process/CI env vars > repository-root `.env.local` > repository-root
  `.env`.
- **Loopback OAuth callback port**: `34338`.
- **Redirect URIs**: `http://127.0.0.1:34338/callback` (loopback) and
  `https://app.t3.codes/connect/callback` (hosted out-of-band).
- **Desktop custom URL schemes**: `t3code-dev://app/` (dev), `t3code://app/` (packaged).
- **Production macOS bundle ID**: `com.t3tools.t3code`.
- **Tunnel binary**: a pinned, managed `cloudflared` build, installed by `t3 connect link`.

## When To Use

Reach for T3 Connect when direct WebSocket access ([[concepts/remote-access]]) isn't viable — the
host is behind NAT, there's no way to open inbound ports, or you want a mobile client to reach a
desktop-hosted environment without any router/firewall configuration. It's also the mechanism an
operator sets up once for a self-hosted or team deployment (via the relay's own Clerk/Cloudflare
configuration).

## Risks & Pitfalls

- `CLERK_SECRET_KEY` must never appear in a client application environment, the desktop app, or be
  committed to the repository — only `infra/relay` server-side config and Alchemy secrets should
  hold it.
- Enabling an **empty** Clerk allowlist blocks all new sign-ups — a documented footgun for closed
  deployments.
- Clerk allowlists control sign-up only; they do not revoke an existing user's active session —
  banning the user in Clerk is required to end active sessions and block future sign-in.
- Omitting the hosted out-of-band redirect URI breaks both headless and SSH authorization.
- The `prod` Alchemy stage owns the retained PlanetScale database; deploy `prod` before creating a
  personal developer stage, since non-production stages reference that same database.

## Related Concepts

- [[concepts/remote-access]]
- [[concepts/background-service]]
- [[concepts/t3code-overview]]

## Sources

- raw/github_doc-docs-internals-t3-connect-md.md
- raw/github_doc-docs-internals-connection-runtime-md.md
