| 1 | # T3 Connect setup |
| 2 | |
| 3 | Deployment and client configuration for T3 Connect. The [architecture note](../internals/t3-connect.md) |
| 4 | explains the trust boundaries; the [relay README](../../infra/relay/README.md#deployment) owns relay |
| 5 | provisioning instructions. |
| 6 | |
| 7 | ## Public application configuration |
| 8 | |
| 9 | T3 Connect is disabled in a fresh clone. To build against the production deployment, copy the |
| 10 | repository-root example: |
| 11 | |
| 12 | ```sh |
| 13 | cp .env.example .env |
| 14 | ``` |
| 15 | |
| 16 | For another deployment, set these values in the repository-root `.env` or `.env.local`: |
| 17 | |
| 18 | ```dotenv |
| 19 | T3CODE_CLERK_PUBLISHABLE_KEY=<publishable key> |
| 20 | T3CODE_CLERK_JWT_TEMPLATE=<JWT template name> |
| 21 | T3CODE_CLERK_CLI_OAUTH_CLIENT_ID=<public OAuth application client ID> |
| 22 | T3CODE_RELAY_URL=https://relay.example.com |
| 23 | ``` |
| 24 | |
| 25 | Process variables take precedence over `.env.local`, then `.env`. Use these canonical names; |
| 26 | the build loader supplies framework-specific aliases. These values are public identifiers. |
| 27 | `CLERK_SECRET_KEY` belongs only in the relay's secrets, never in client configuration. |
| 28 | |
| 29 | Client and bundled-server builds embed the public values, so set them before building. |
| 30 | EAS preview and production environments need the publishable key, JWT template name, and relay URL. |
| 31 | Bundled servers also accept runtime overrides for operator-managed deployments. |
| 32 | |
| 33 | Copy `infra/relay/.env.example` to `infra/relay/.env` for relay deployment settings. |
| 34 | Deploy `prod` before personal stages because it owns the retained database that their branches |
| 35 | depend on. The stack's `PublishClientConfig` action writes the resulting relay URL back to the root `.env`. |
| 36 | |
| 37 | ## CLI OAuth application |
| 38 | |
| 39 | In Clerk's OAuth applications settings: |
| 40 | |
| 41 | 1. Create a public OAuth application for the T3 CLI, using authorization-code exchange with PKCE. |
| 42 | 2. Allow the redirect URI `http://127.0.0.1:34338/callback`. |
| 43 | 3. Enable the `openid`, `profile`, `email`, and `offline_access` scopes. |
| 44 | 4. Enable **Device authorization grant** on the application. Headless and SSH authorization use |
| 45 | it, and Clerk only advertises the device endpoint once it is on. The feature is in beta and |
| 46 | Clerk enables it per account on request. |
| 47 | 5. Set `T3CODE_CLERK_CLI_OAUTH_CLIENT_ID` to the generated public client ID in local and release |
| 48 | build environments. |
| 49 | |
| 50 | ## JWT template |
| 51 | |
| 52 | Create a Clerk JWT template named `t3-relay` with claims: |
| 53 | |
| 54 | ```json |
| 55 | { "aud": "t3-code-relay" } |
| 56 | ``` |
| 57 | |
| 58 | Set `T3CODE_CLERK_JWT_TEMPLATE=t3-relay` for clients and |
| 59 | `CLERK_JWT_AUDIENCE=t3-code-relay` for the relay. The production relay deployment environment |
| 60 | also defines `CLERK_JWT_TEMPLATE`. The audience stays the same across relay stages; the relay |
| 61 | URL selects the deployment. |
| 62 | |
| 63 | ## Desktop OAuth redirects |
| 64 | |
| 65 | Enable Clerk's Native API and add the desktop redirects to its SSO redirect allowlist: |
| 66 | |
| 67 | ```text |
| 68 | t3code-dev://app/ |
| 69 | t3code://app/ |
| 70 | ``` |
| 71 | |
| 72 | Add the corresponding origin to the Clerk instance's Backend API `allowed_origins` array. |
| 73 | Development uses `t3code-dev://app`; production uses `t3code://app`. Update the array with |
| 74 | `PATCH https://api.clerk.com/v1/instance` using the Clerk secret key, preserving existing entries. |
| 75 | The Clerk Electron integration handles token |
| 76 | persistence and system-browser callback delivery. |
| 77 | |
| 78 | ## Android native sign-in redirects |
| 79 | |
| 80 | Clerk's native Android SDK uses `clerk://<applicationId>.callback`. In the Clerk instance selected by the app's publishable key, add each supported package to **Native applications > Allowlist for mobile SSO redirect**: |
| 81 | |
| 82 | | Variant | Callback | |
| 83 | | ----------- | --------------------------------------------- | |
| 84 | | Development | `clerk://com.t3tools.t3code.dev.callback` | |
| 85 | | Preview | `clerk://com.t3tools.t3code.preview.callback` | |
| 86 | | Production | `clerk://com.t3tools.t3code.callback` | |
| 87 | |
| 88 | Preserve existing entries. These callbacks are separate from the `t3code-dev` / `t3code-preview` / `t3code` navigation schemes. A private development build using the production Clerk key still needs its development callback allowed by that instance's administrator; rebuilding the same package does not change the allowlist. |
| 89 | |
| 90 | ## Desktop passkeys |
| 91 | |
| 92 | For a production macOS app with bundle ID `com.t3tools.t3code`: |
| 93 | |
| 94 | 1. Create an explicit macOS App ID in the Apple Developer portal with **Associated Domains**. |
| 95 | 2. Create a provisioning profile for that App ID and the distribution signing certificate. |
| 96 | 3. In Clerk's Native API settings, add an iOS app with the same Apple Team ID and bundle ID. |
| 97 | This setting also configures Electron/macOS passkeys. |
| 98 | 4. Check `https://<frontend-api>/.well-known/apple-app-site-association`. Its |
| 99 | `webcredentials.apps` must include `<TEAM_ID>.com.t3tools.t3code`. |
| 100 | 5. Configure signing as described in the [release runbook](./release.md#2-apple-signing--notarization-setup-macos). |
| 101 | |
| 102 | Local signed builds additionally use: |
| 103 | |
| 104 | ```dotenv |
| 105 | T3CODE_APPLE_TEAM_ID=ABC1234567 |
| 106 | T3CODE_MACOS_PROVISIONING_PROFILE=/absolute/path/to/t3code.provisionprofile |
| 107 | # Override only when the RP domain differs from the Clerk Frontend API hostname. |
| 108 | T3CODE_CLERK_PASSKEY_RP_DOMAINS=example.clerk.accounts.dev,clerk.example.com |
| 109 | ``` |
| 110 | |
| 111 | Without the override, the build derives the RP domain from the Clerk publishable key. |
| 112 | After changing Associated Domains, bump the build version before rebuilding. macOS can otherwise |
| 113 | reuse stale Shared Web Credentials metadata for the same app/version pair. |
| 114 | |
| 115 | The ordinary `dev:desktop` launcher is unsigned and cannot exercise macOS passkeys. For renderer |
| 116 | HMR, install a signed build, start `vp run dev:web`, and launch the installed executable with the |
| 117 | actual web and server ports. For example, with the default ports: |
| 118 | |
| 119 | ```sh |
| 120 | VITE_DEV_SERVER_URL=http://127.0.0.1:5733 \ |
| 121 | T3CODE_PORT=13773 \ |
| 122 | "/Applications/T3 Code (Alpha).app/Contents/MacOS/T3 Code (Alpha)" |
| 123 | ``` |
| 124 | |
| 125 | Rebuild the signed app after native dependency, main-process, preload, entitlement, provisioning, |
| 126 | or signing changes. Renderer edits can reuse it. Verify the installed bundle before testing: |
| 127 | |
| 128 | ```sh |
| 129 | codesign --verify --deep --strict "/Applications/T3 Code (Alpha).app" |
| 130 | codesign -d --entitlements :- "/Applications/T3 Code (Alpha).app" |
| 131 | ``` |
| 132 | |
| 133 | ## Restricting sign-ups |
| 134 | |
| 135 | Use Clerk's allowlist for permitted email addresses or domains, or Restricted mode for invitation-only |
| 136 | sign-up. An enabled empty allowlist blocks all new sign-ups. |
| 137 | |
| 138 | Sign-up restrictions do not revoke an existing account's access. Ban the account in Clerk when |
| 139 | its active sessions and future sign-ins must be disabled. |