Zum Hauptinhalt springen
Verbindungen sind Anmeldedaten, die ein Benutzer für einen externen Dienst besitzt (Linear, GitHub, Slack, …). Ihre App legt fest, wie diese Anmeldedaten bezogen werden — ein Verbindungsanbieter — und verwendet sie zur Laufzeit, um authentifizierte Aufrufe an die Drittanbieter-API zu tätigen. Derzeit wird nur OAuth 2.0 unterstützt. Zukünftige Anmeldedatentypen (Personal Access Tokens, API-Schlüssel, Basic Auth) werden in dieselbe Oberfläche integriert — Apps, die bereits defineConnectionProvider({ type: 'oauth', ... }) müssen nicht migriert werden.
Ein Verbindungsanbieter beschreibt den OAuth-Handshake, den Ihre App benötigt. Der Benutzer klickt in den Einstellungen Ihrer App auf “Verbindung hinzufügen”, schließt den Zustimmungsbildschirm des Anbieters ab, und in seinem Arbeitsbereich wird eine ConnectedAccount-Zeile erstellt.Eine funktionierende Einrichtung benötigt zwei Dateien — den Verbindungsanbieter und eine passende serverVariables-Deklaration in defineApplication, die die OAuth-Client-Anmeldedaten enthält.
src/connection-providers/linear-connection.ts
import { defineConnectionProvider } from 'twenty-sdk/define';

export default defineConnectionProvider({
  universalIdentifier: '9c7d1f5e-6a0b-4d44-be0c-3f8b5a9d4e6f',
  name: 'linear',
  displayName: 'Linear',
  icon: 'IconBrandLinear',
  type: 'oauth',
  oauth: {
    authorizationEndpoint: 'https://linear.app/oauth/authorize',
    tokenEndpoint: 'https://api.linear.app/oauth/token',
    scopes: ['read', 'write'],
    // These must match keys in `defineApplication.serverVariables` below.
    clientIdVariable: 'LINEAR_CLIENT_ID',
    clientSecretVariable: 'LINEAR_CLIENT_SECRET',
    // Optional: defaults to 'json'. Some providers (Linear, Slack) want
    // 'form-urlencoded' for the token request.
    tokenRequestContentType: 'form-urlencoded',
    // Optional: defaults to true. Disable only if the provider rejects PKCE.
    usePkce: false,
    // Optional: extra query params on the authorize URL.
    // authorizationParams: { prompt: 'consent' },
    // Optional: provider's RFC 7009 token revocation endpoint, called on disconnect.
    // revokeEndpoint: 'https://example.com/oauth/revoke',
  },
});
src/application.config.ts
import { defineApplication } from 'twenty-sdk/define';

export default defineApplication({
  universalIdentifier: '...',
  displayName: 'Linear',
  description: 'Connect Linear to Twenty.',
  // OAuth client credentials live on the app registration (one OAuth app per
  // Twenty server, configured by the admin) — not per-workspace. Declare them
  // as serverVariables so the admin can fill them in once for all installs.
  serverVariables: {
    LINEAR_CLIENT_ID: {
      description: 'OAuth client ID from your Linear OAuth application.',
      isSecret: false,
      isRequired: true,
    },
    LINEAR_CLIENT_SECRET: {
      description: 'OAuth client secret from your Linear OAuth application.',
      isSecret: true,
      isRequired: true,
    },
  },
});
Hauptpunkte:
  • name ist die eindeutige Bezeichner-Zeichenfolge, die in listConnections({ providerName }) verwendet wird (kebab-case, muss ^[a-z][a-z0-9-]*$ entsprechen).
  • displayName wird im Einstellungs-Tab der jeweiligen App und in der KI-Toolliste angezeigt.
  • clientIdVariable / clientSecretVariable sind Namen, keine Werte — sie müssen den in defineApplication.serverVariables deklarierten Schlüsseln entsprechen. Die tatsächlichen client_id und client_secret werden vom Serveradministrator über die App-Registrierungsoberfläche eingegeben und niemals in Ihr Repository eingecheckt.
  • Verwenden Sie serverVariables (nicht applicationVariables) — OAuth-Anmeldedaten gelten serverweit und es gibt eine OAuth-App pro Twenty-Server.
  • Solange beide serverVariables nicht ausgefüllt sind, zeigt der Einstellungs-Tab pro App den Hinweis “Benötigt Server-Admin” an und der Button “Verbindung hinzufügen” ist deaktiviert.
  • type: 'oauth' ist derzeit der einzige unterstützte Wert. Der Diskriminator ist vorwärtskompatibel: zukünftige Typen ('pat', 'api-key', …) werden neue Unterkonfigurationsblöcke neben oauth hinzufügen.
Die OAuth-Callback-URL, die Ihr Anbieter auf die Whitelist setzen muss, lautet:
https://<your-twenty-server>/apps/oauth/callback
Innerhalb eines Logikfunktions-Handlers gibt listConnections({ providerName }) die ConnectedAccount-Zeilen dieser App für den angegebenen Anbieter zurück, mit aktualisierten Zugriffstoken.
src/logic-functions/handlers/create-linear-issue-handler.ts
import { listConnections } from 'twenty-sdk/logic-function';

export const createLinearIssueHandler = async (input: {
  teamId?: string;
  title?: string;
}) => {
  if (!input.teamId || !input.title) {
    return { success: false, error: 'teamId and title are required' };
  }

  const connections = await listConnections({ providerName: 'linear' });

  // Workspace-shared credentials win when present; fall back to the first
  // user-visibility one. For HTTP-route triggers you typically pick the
  // request user's connection via event.userWorkspaceId instead.
  const connection =
    connections.find((c) => c.visibility === 'workspace') ?? connections[0];

  if (!connection) {
    return {
      success: false,
      error:
        'Linear is not connected. Open the app settings and click "Add connection".',
    };
  }

  // Use connection.accessToken to call the third-party API.
  const response = await fetch('https://api.linear.app/graphql', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${connection.accessToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      query: `mutation { issueCreate(input: { teamId: "${input.teamId}", title: "${input.title}" }) { success } }`,
    }),
  });

  return { success: response.ok };
};
Jede Verbindung hat:
FeldBeschreibung
idEindeutige Zeilen-ID; an getConnection(id) übergeben, um eine einzelne Verbindung erneut abzurufen
visibility'user' (privat für ein Mitglied des Arbeitsbereichs) oder 'workspace' (mit allen Mitgliedern geteilt)
scopesVom Upstream-Anbieter gewährte OAuth-Berechtigungen (unabhängig von visibility — diese sind nicht miteinander verknüpft)
userWorkspaceIdDie userWorkspace-ID des Eigentümers — nützlich, um “die Verbindung des anfragenden Benutzers” in HTTP-Routen-Triggern auszuwählen
accessTokenFrisches OAuth-Zugriffstoken (wird bei Ablauf automatisch erneuert)
name / handleAnzeigename der Verbindung (automatisch beim OAuth-Callback abgeleitet, vom Benutzer umbenennbar)
authFailedAtGesetzt, wenn die jüngste Aktualisierung fehlgeschlagen ist; der Benutzer muss die Verbindung erneut herstellen
Hauptpunkte:
  • Übergeben Sie { providerName }, um nach Anbieter zu filtern; lassen Sie es weg, um alle Verbindungen dieser App über alle Anbieter hinweg zu erhalten.
  • Der Server aktualisiert das Zugriffstoken vor der Rückgabe transparent. Ihr Handler sieht stets ein verwendbares Token (oder authFailedAt ist gesetzt).
  • getConnection(id) ist das Pendant für eine einzelne Zeile.
Wenn ein Benutzer auf “Verbindung hinzufügen” klickt, wird er aufgefordert, eine Sichtbarkeit auszuwählen:
  • Nur für mich — die Anmeldedaten sind für den sich verbindenden Benutzer privat. Jede Logikfunktion, die in seinem/ihrem Auftrag aufgerufen wird (HTTP-Routen-Trigger mit isAuthRequired: true), sieht sie; Cron-Trigger und Datenbankereignisse nicht.
  • Im Arbeitsbereich geteilt — jedes Arbeitsbereichsmitglied kann die Anmeldedaten verwenden. Cron-/Datenbank-Trigger sehen sie ebenfalls, da sie keinen anfragenden Benutzer haben.
Verwenden Sie für jeden Handler die richtige Option:
// HTTP-route trigger — prefer the request user's own connection.
const conn =
  connections.find((c) => c.userWorkspaceId === event.userWorkspaceId) ??
  connections.find((c) => c.visibility === 'workspace');

// Cron trigger — no request user; only shared credentials are sensible.
const conn = connections.find((c) => c.visibility === 'workspace');
Mehrere Verbindungen pro (Benutzer, Anbieter) sind erlaubt, sodass derselbe Benutzer “Persönliches Linear” und “Arbeits-Linear” nebeneinander haben kann.
Für jeden Verbindungsanbieter muss der Serveradministrator zunächst eine OAuth-App beim Drittanbieter registrieren.
  1. Gehen Sie zu den Entwickler-Einstellungen des Anbieters (z. B. https://linear.app/settings/api/applications/new).
  2. Setzen Sie die Redirect-URI auf \<SERVER_URL>/apps/oauth/callback.
  3. Kopieren Sie die generierte Client ID und das Client Secret.
  4. Öffnen Sie die installierte App in Twenty als Serveradministrator → setzen Sie die Werte in den entsprechenden serverVariables.
  5. Mitglieder des Arbeitsbereichs können dann Verbindungen im Verbindungen-Abschnitt der jeweiligen App hinzufügen.