Skip to main content
Connections are credentials a user holds for an external service (Linear, GitHub, Slack, …). Your app declares how those credentials are obtained — a connection provider — and consumes them at runtime to make authenticated calls to the third-party API. Today only OAuth 2.0 is supported. Future credential types (personal access tokens, API keys, basic auth) will plug into the same surface — apps already using defineConnectionProvider({ type: 'oauth', ... }) won’t need to migrate.
A connection provider describes the OAuth handshake your app needs. The user clicks “Add connection” in your app’s settings, completes the provider’s consent screen, and a ConnectedAccount row is created in their workspace.A working setup needs two files — the connection provider, and a matching serverVariables declaration on defineApplication that holds the OAuth client credentials.
src/connection-providers/linear-connection.ts
src/application.config.ts
Key points:
  • name is the unique identifier string used in listConnections({ providerName }) (kebab-case, must match ^[a-z][a-z0-9-]*$).
  • displayName shows in the per-app settings tab and in the AI tool list.
  • clientIdVariable / clientSecretVariable are names, not values — they must match keys declared in defineApplication.serverVariables. The actual client_id and client_secret are entered by the server admin through the app registration UI, never committed to your repo.
  • Use serverVariables (not applicationVariables) — OAuth credentials are server-wide and one OAuth app per Twenty server.
  • Until both serverVariables are filled in, the per-app settings tab shows a “needs server admin” hint and the “Add connection” button is disabled.
  • type: 'oauth' is the only supported value today. The discriminator is forward-compatible: future types ('pat', 'api-key', …) will add new sub-config blocks alongside oauth.
The OAuth callback URL your provider needs to whitelist is:
Some providers hand you data at connect time that you need to persist before the connection is usable — the classic example is Slack, where the OAuth response identifies the workspace’s team_id that inbound events will be keyed by. Set onConnectLogicFunction to reference a logic function in the same app (by its universalIdentifier), and it runs right after the ConnectedAccount is created.
src/connection-providers/slack-connection.ts
The hook runs asynchronously in the connecting workspace (it is enqueued, not awaited), so a slow or failing hook never blocks or breaks the OAuth callback — make it idempotent and handle its own retries. The handler receives:
From there use getConnection(connectedAccountId) to read the fresh access token and call the provider’s API (e.g. Slack auth.test) or persist a mapping with the key-value store.
Inside a logic function handler, listConnections({ providerName }) returns this app’s ConnectedAccount rows for the given provider, with refreshed access tokens.
src/logic-functions/handlers/create-linear-issue-handler.ts
Each connection has:Key points:
  • Pass { providerName } to filter by provider; omit it to get all connections this app owns across all providers.
  • The server transparently refreshes the access token before returning. Your handler always sees a usable token (or authFailedAt set).
  • getConnection(id) is the single-row equivalent.
When a user clicks “Add connection,” they’re prompted to pick a visibility:
  • Just for me — the credential is private to the connecting user. Any logic function called on their behalf (HTTP-route trigger with isAuthRequired: true) sees it; cron triggers and database events do not.
  • Workspace shared — any workspace member can use the credential. Cron / database triggers also see it, since they have no request user.
Use the right one for each handler:
Multiple connections per (user, provider) are allowed, so the same user can hold “Personal Linear” and “Work Linear” side by side.
For each connection provider, the server admin needs to register an OAuth app at the third party first.
  1. Go to the provider’s developer settings (e.g. https://linear.app/settings/api/applications/new).
  2. Set the Redirect URI to <SERVER_URL>/auth/apps/callback.
  3. Copy the generated Client ID and Client Secret.
  4. Open the installed app in Twenty as a server admin → set the values on the corresponding serverVariables.
  5. Workspace members can then add connections from the per-app Connections section.