---
title: Connessioni
description: Consenti alla tua app di agire per conto di un utente nei servizi di terze parti tramite OAuth.
icon: plug
---

Le connessioni sono credenziali che un utente detiene per un servizio esterno (Linear, GitHub, Slack, ...). La tua app dichiara **come** vengono ottenute tali credenziali — un **provider di connessione** — e le utilizza in fase di esecuzione per effettuare chiamate autenticate all'API di terze parti.

Oggi è supportato solo OAuth 2.0. Tipi di credenziali futuri (token di accesso personali, chiavi API, autenticazione di base) si integreranno nella stessa interfaccia — le app che già usano `defineConnectionProvider({ type: 'oauth', ... })` non dovranno migrare.

<AccordionGroup>

<Accordion title="defineConnectionProvider" description="Dichiara come vengono ottenute le connessioni della tua app">

Un provider di connessione descrive l'handshake OAuth di cui la tua app ha bisogno. L'utente fa clic su "Aggiungi connessione" nelle impostazioni della tua app, completa la schermata di consenso del provider e viene creata una riga `ConnectedAccount` nel suo spazio di lavoro.

Una configurazione funzionante richiede **due file** — il provider di connessione e una dichiarazione `serverVariables` corrispondente su `defineApplication` che contiene le credenziali client OAuth.

```ts 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',
  },
});
```

```ts 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,
    },
  },
});
```

Punti chiave:

* `name` è la stringa identificativa univoca usata in `listConnections({ providerName })` (kebab-case, deve corrispondere a `^[a-z][a-z0-9-]*$`).
* `displayName` viene mostrato nella scheda delle impostazioni per app e nell'elenco degli strumenti AI.
* `clientIdVariable` / `clientSecretVariable` sono **nomi**, non valori — devono corrispondere alle chiavi dichiarate in `defineApplication.serverVariables`. I `client_id` e `client_secret` effettivi vengono inseriti dall'amministratore del server tramite l'interfaccia di registrazione dell'app e non vengono mai aggiunti al tuo repository.
* Usa `serverVariables` (non `applicationVariables`) — le credenziali OAuth sono a livello di server e c'è una sola app OAuth per ogni server Twenty.
* Finché entrambe le `serverVariables` non sono compilate, la scheda delle impostazioni per app mostra un suggerimento "richiede l'amministratore del server" e il pulsante "Aggiungi connessione" è disattivato.
* `type: 'oauth'` è l'unico valore supportato oggi. Il discriminatore è compatibile con versioni future: tipi futuri (`'pat'`, `'api-key'`, ...) aggiungeranno nuovi blocchi di sotto-configurazione accanto a `oauth`.

L'URL di callback OAuth che il tuo provider deve inserire nella whitelist è:

```
https://<your-twenty-server>/auth/apps/callback
```

</Accordion>

<Accordion title="listConnections / getConnection" description="Usa le connessioni da una funzione di logica">

All'interno di un gestore di funzione di logica, `listConnections({ providerName })` restituisce le righe `ConnectedAccount` di questa app per il provider indicato, con token di accesso aggiornati.

```ts 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 };
};
```

Ogni connessione ha:

| Campo             | Descrizione                                                                                                                        |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `id`              | ID di riga univoco; passalo a `getConnection(id)` per recuperarne una singola connessione                                          |
| `visibility`      | `'user'` (privata per un membro dello spazio di lavoro) oppure `'workspace'` (condivisa con tutti i membri)                        |
| `scopes`          | Autorizzazioni OAuth concesse dal provider a monte (distinte da `visibility` — non sono correlate)                                 |
| `userWorkspaceId` | L'id userWorkspace del proprietario — utile per selezionare "la connessione dell'utente della richiesta" nei trigger di route HTTP |
| `accessToken`     | Token di accesso OAuth aggiornato (rinnovato automaticamente se scaduto)                                                           |
| `name` / `handle` | Il nome visualizzato della connessione (derivato automaticamente al callback OAuth, rinominabile dall'utente)                      |
| `authFailedAt`    | Impostato quando l'aggiornamento più recente non è riuscito; l'utente deve riconnettersi                                           |

Punti chiave:

* Passa `{ providerName }` per filtrare per provider; omettilo per ottenere tutte le connessioni possedute da questa app su tutti i provider.
* Il server rinnova in modo trasparente il token di accesso prima di restituire la risposta. Il tuo handler vede sempre un token utilizzabile (oppure `authFailedAt` impostato).
* `getConnection(id)` è l'equivalente a singola riga.

</Accordion>

<Accordion title="Visibilità per utente vs condivisa nello spazio di lavoro" description="Come gli utenti scelgono tra credenziali private e condivise">

Quando un utente fa clic su "Aggiungi connessione", viene richiesto di scegliere una visibilità:

* **Solo per me** — la credenziale è privata per l'utente che effettua la connessione. Qualsiasi funzione di logica chiamata per loro conto (trigger di route HTTP con `isAuthRequired: true`) la vede; i trigger cron e gli eventi del database no.
* **Condivisa nello spazio di lavoro** — qualsiasi membro dello spazio di lavoro può usare la credenziale. Anche i trigger cron/database la vedono, poiché non hanno un utente della richiesta.

Usa quella giusta per ciascun handler:

```ts
// 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');
```

Sono consentite più connessioni per (utente, provider), quindi lo stesso utente può avere affiancate "Linear personale" e "Linear di lavoro".

</Accordion>

<Accordion title="Configurazione una tantum del provider" description="Registra la tua app OAuth presso il servizio di terze parti">

Per ciascun provider di connessione, l'amministratore del server deve prima registrare un'app OAuth presso il servizio di terze parti.

1. Vai alle impostazioni sviluppatore del provider (ad es. https://linear.app/settings/api/applications/new).
2. Imposta la **Redirect URI** su `\<SERVER_URL>/auth/apps/callback`.
3. Copia il **Client ID** e il **Client Secret** generati.
4. Apri l'app installata in Twenty come amministratore del server → imposta i valori nelle corrispondenti `serverVariables`.
5. I membri dello spazio di lavoro possono quindi aggiungere connessioni dalla sezione **Connessioni** dell'app.

</Accordion>

</AccordionGroup>
