Panoramica
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. OAuth 2.0 è integrato. I servizi con un proprio flusso di connessione — una pagina di accesso ospitata, un ID dell’account recapitato tramite webhook — usano un providercustom, in cui la tua app gestisce il flusso e Twenty conserva l’utente, lo spazio di lavoro e la connessione salvata. 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.
defineConnectionProvider
Dichiara come vengono ottenute le connessioni della tua app
defineConnectionProvider
Dichiara come vengono ottenute le connessioni della tua app
WORKSPACE (quello predefinito), un membro 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. Consulta “Connessioni dello spazio di lavoro o personali” per i provider USER.Una configurazione funzionante richiede due file — il provider di connessione e una dichiarazione serverVariables corrispondente su defineApplication che contiene le credenziali client OAuth.nameè la stringa identificativa univoca usata inlistConnections({ providerName })(kebab-case, deve corrispondere a^[a-z][a-z0-9-]*$).displayNameviene mostrato nella scheda Generale dell’app e nell’elenco degli strumenti AI.scopestabilisce chi si connette:'WORKSPACE'(il valore predefinito) per le connessioni condivise con l’intero spazio di lavoro,'USER'per le connessioni che ciascun membro crea per sé. Consulta “Connessioni dello spazio di lavoro o personali” qui sotto.logoè un percorso a una risorsa inclusa nella cartellapublic/della tua app, fornita tramite le risorse pubbliche dell’app. Quando omessa, la scheda Generale utilizza un segnaposto creato dadisplayName.clientIdVariable/clientSecretVariablesono nomi, non valori — devono corrispondere alle chiavi dichiarate indefineApplication.serverVariables. Iclient_ideclient_secreteffettivi vengono inseriti dall’amministratore del server tramite l’interfaccia di registrazione dell’app e non vengono mai aggiunti al tuo repository.- Usa
serverVariables(nonapplicationVariables) — le credenziali OAuth sono a livello di server e c’è una sola app OAuth per ogni server Twenty. - Finché entrambe le
serverVariablesnon sono compilate, la scheda Generale dell’app mostra un suggerimento “richiede l’amministratore del server” e il pulsante “Aggiungi connessione” è disattivato. typeè'oauth'(con un bloccooauth) o'custom'(con un bloccocustom, vedi “Flussi di connessione personalizzati”). Il discriminatore è compatibile con versioni future: tipi futuri ('pat','api-key', …) aggiungerà nuovi blocchi di sotto-configurazione accanto a questi.
Flussi di connessione personalizzati
Connetti servizi che non sono provider OAuth
Flussi di connessione personalizzati
Connetti servizi che non sono provider OAuth
type: 'custom' e due funzioni logiche:authorizeLogicFunction con un callbackUrl che lo contiene. Restituisci dove inviare l’utente:callbackUrl al servizio senza modificarlo. Twenty lo accetta come reindirizzamento del browser (GET) e come notifica dal server (POST) ed esegue callbackLogicFunction per ogni richiesta con il relativo metodo, parametri di query (senza state), intestazioni, corpo analizzato e rawBody (i byte esatti della richiesta, null per GET). Restituisce l’account dimostrato dalla richiesta oppure null quando non ne contiene alcuno — in genere, il browser che torna mentre l’ID dell’account viene trasmesso tramite notifica:callbackUrl dimostra solo che la richiesta contiene tale URL, non che sia stata inviata dal servizio. Quando il servizio firma le proprie notifiche, verifica la firma su rawBody prima di considerare attendibile il corpo. Le intestazioni sono in minuscolo e cookie, authorization e proxy-authorization non vengono mai inoltrati:onConnectLogicFunction non viene eseguita. onConnectLogicFunction viene eseguita quando una connessione viene creata, riconnessa o ripristinata, ma non di nuovo quando il servizio segnala un account già connesso. Lo stato scade dopo un’ora, quindi una notifica che arriva più tardi viene rifiutata. I servizi spesso ritentano le notifiche: una ripetizione per un account già connesso aggiorna quella connessione, quindi restituire di nuovo lo stesso account è sicuro.Twenty non aggiorna né revoca le connessioni personalizzate. Rilascia ciò che il servizio conserva per l’account in onDisconnectLogicFunction.Il type di un provider, come il relativo scope, non può cambiare dopo la sincronizzazione: per spostare un servizio tra oauth e custom, dichiara un nuovo provider con un nuovo universalIdentifier.I provider personalizzati sono disponibili con Twenty 2.52.0.Identifica l'account collegato
Impedisci che una riconnessione cambi silenziosamente gli account upstream
Identifica l'account collegato
Impedisci che una riconnessione cambi silenziosamente gli account upstream
identifyAccountLogicFunction su una funzione logica nella stessa app che restituisce un ID stabile per l’account associato al token appena emesso:timeoutSeconds della funzione a 10, indipendentemente da quanto dichiarato dal manifest; limita la richiesta a una sola chiamata all’endpoint “chi sono” del provider. L’hook on-connect, se presente, viene comunque eseguito successivamente, una volta salvata la connessione.Payload. Il gestore riceve il token di accesso provvisorio. Non è ancora stato reso persistente, quindi getConnection non può restituirlo; usalo direttamente e non registrarlo nei log.externalAccountIddeve essere stabile per tutta la durata dell’account upstream (un id del team, un id dell’organizzazione, un id dell’utente), mai un nome che l’utente può modificare. Twenty lo rimuove e lo memorizza nella connessione al primo collegamento.handle, quando restituito, sostituisce l’handle che Twenty altrimenti deriverebbe (l’email OIDC diid_tokeno l’email dell’utente che si collega). Restituisci qualcosa che un utente riconosca, ad esempio il nome dello spazio di lavoro Slack.- Restituisci
{ externalAccountId: null }quando il provider non dispone di un id stabile da offrire. Twenty si comporta quindi come se non fosse stata dichiarata alcuna funzione di identificazione: non viene memorizzato alcun id, una riconnessione cancella qualsiasi id memorizzato in precedenza e le riconnessioni non vengono verificate. Un semplicenullo un return mancante viene trattato come errore, quindi un gestore che dimentica di restituire un valore non può disabilitare silenziosamente il controllo. - Se la funzione genera un’eccezione, supera il timeout o restituisce qualsiasi altra cosa, la connessione non viene salvata e l’utente torna alla pagina delle impostazioni con un errore. Genera un’eccezione solo quando non puoi effettivamente identificare l’account.
externalAccountId restituito con quello memorizzato nella connessione. Se differiscono, il callback viene rifiutato prima che venga scritto alcunché: i token esistenti, l’handle e l’ambito restano invariati, l’hook on-connect non viene eseguito e l’utente vede quale account ha autorizzato e a quale account appartiene la connessione. Le connessioni create prima che l’app dichiarasse la funzione non hanno ancora alcun id memorizzato; la loro successiva riconnessione lo memorizza.Twenty non rimuove i duplicati in base a externalAccountId: collegare due volte lo stesso account upstream tramite Aggiungi connessione crea due connessioni. L’id è esposto in listConnections e getConnection, quindi un’app che desidera una connessione per account upstream può rilevare autonomamente i duplicati (ad esempio nel proprio hook on-connect).Scrittura della funzione. La maggior parte dei provider espone un singolo endpoint che descrive il token corrente. Per Slack si tratta di auth.test, che restituisce lo spazio di lavoro (team_id, team) e l’utente associato al token:String(id).L’identificazione è disponibile con Twenty 2.48.0. Se la tua app dipende da questa funzionalità, dichiara "engines": { "twenty": ">=2.48.0" } nel relativo package.json.Esegui una funzione logica al momento della connessione
Reagisci non appena viene stabilita una connessione
Esegui una funzione logica al momento della connessione
Reagisci non appena viene stabilita una connessione
team_id dell’area di lavoro che fungerà da chiave per gli eventi in ingresso. Imposta onConnectLogicFunction per fare riferimento a una funzione logica nella stessa app (tramite il suo universalIdentifier), e questa verrà eseguita subito dopo la creazione di ConnectedAccount.getConnection(connectedAccountId) per leggere il token di accesso aggiornato e chiamare l’API del provider (ad es. Slack auth.test) o salvare una mappatura con il key-value store.Esegui una funzione logica alla disconnessione
Effettua la pulizia quando una connessione viene disconnessa o rimossa.
Esegui una funzione logica alla disconnessione
Effettua la pulizia quando una connessione viene disconnessa o rimossa.
team_id al momento della connessione deve rilasciare tale rivendicazione, in modo che un’altra area di lavoro possa connettere lo stesso team Slack. Imposta onDisconnectLogicFunction in modo che faccia riferimento a una funzione logica nella stessa app; verrà eseguita quando la connessione viene disconnessa e di nuovo quando viene eliminata.ConnectedAccount e il relativo token sono ancora presenti, quindi getConnection(connectedAccountId) viene risolto e il gestore può rilasciare tutto ciò che ha registrato in remoto. In caso di eliminazione, le credenziali potrebbero essere già state rimosse (un membro può eliminare una connessione che aveva disconnesso in precedenza), quindi rendi il gestore idempotente e conserva lo stato necessario (un team_id, un id di sottoscrizione esterno) nell’archivio chiave-valore, scritto al momento della connessione e associato a connectedAccountId. Mantienilo breve: viene eseguito all’interno della richiesta, quindi il relativo timeoutSeconds rappresenta il limite massimo della durata di tale richiesta.L’hook viene attivato quando una connessione viene disconnessa o rimossa autonomamente. La disinstallazione dell’app elimina le sue connessioni tramite una cascata del database, quindi in questo caso l’hook non viene eseguito. Dichiara una uninstallLogicFunction su defineApplication per quel percorso: viene eseguita prima che i metadati dell’app vengano eliminati, così può ancora chiamare listConnections ed eseguire il cleanup di ciò che resta.listConnections / getConnection
Usa le connessioni da una funzione di logica
listConnections / getConnection
Usa le connessioni da una funzione di logica
listConnections({ providerName }) restituisce le righe ConnectedAccount di questa app per il provider indicato, con token di accesso aggiornati.- 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
authFailedAtimpostato). getConnection(id)è l’equivalente a singola riga.
reportConnectionAuthFailure
Informa la piattaforma che una credenziale non è valida
reportConnectionAuthFailure
Informa la piattaforma che una credenziale non è valida
authFailedAt solo quando il rinnovo OAuth non riesce. I provider i cui token non vengono mai rinnovati (ad esempio, un token bot di Slack) non riescono solo al momento della chiamata all’interno dei gestori, pertanto la riga della connessione nelle impostazioni continuerebbe a mostrare Connesso mentre ogni chiamata fallisce. Quando il codice rileva un rifiuto di autenticazione definitivo, segnalalo:authFailedAt e il motivo facoltativo sulla connessione. La riga nelle impostazioni passa a Riconnessione necessaria con un pulsante Riconnetti, la pagina dei dettagli della connessione mostra il motivo e getConnection inizia a generare AppConnectionAuthFailedError per quella riga. Il flag e il motivo vengono cancellati automaticamente quando l’utente si riconnette. Un reason più lungo di 1000 caratteri viene rifiutato, quindi tronca i payload del provider prima di passarli.Segnala solo gli errori che una riconnessione risolverebbe effettivamente (un rifiuto della classe invalid_auth dal provider), mai errori di rete transitori. Un’app può indicare solo le proprie connessioni e un utente della richiesta può indicare solo le proprie credenziali personali.La mutazione alla base di questo helper è disponibile con Twenty 2.40.0, quindi chiamarla su un server meno recente non riesce. Se l’app la usa, dichiara la dipendenza nel tuo package.json: "engines": { "twenty": ">=2.40.0" }.Connessioni dello spazio di lavoro o personali
Scegli chi si connette con l'ambito del provider
Connessioni dello spazio di lavoro o personali
Scegli chi si connette con l'ambito del provider
- Condivisa nello spazio di lavoro (
'WORKSPACE') — qualsiasi membro dello spazio di lavoro può usare la credenziale. Anche i trigger cron/database la vedono, poiché non hanno un utente della richiesta. - Solo per me (
'USER') — la credenziale appartiene al membro che effettua la connessione. Nelle esecuzioni effettuate per conto di un membro (trigger della route HTTP conisAuthRequired: true),listConnectionsrestituisce le connessioni condivise più quelle del membro stesso efindConnectionForRequestseleziona la connessione personale del membro, ricorrendo a una condivisa quando non ne possiede una. Nelle esecuzioni senza un utente della richiesta (ad esempio, trigger cron),listConnectionsrestituisce ogni connessione, incluse quelle personali di ciascun membro.
scope del provider stabilisce quale ambito riceveranno le sue nuove connessioni:scope: 'WORKSPACE'(il valore predefinito) — l’app funziona con connessioni condivise con lo spazio di lavoro. Aggiungi connessione nelle impostazioni dello spazio di lavoro dell’app crea una connessione condivisa nello spazio di lavoro.scope: 'USER'— ciascun membro connette il proprio account, creando connessioni personali. I membri li aggiungono, ricollegano e rimuovono dalla pagina dell’app in Impostazioni > Utente > Preferenze app, che richiede l’autorizzazione App utente. Le impostazioni dello spazio di lavoro dell’app non dispongono del pulsante Aggiungi connessione per un providerUSER.
USER, quindi non fare affidamento su una per
una funzionalità di cui ogni spazio di lavoro ha bisogno ora.scope di un provider esistente e l’aggiornamento viene rifiutato se tenta di farlo. Per spostare un servizio da un ambito all’altro, dichiara un nuovo provider con un nuovo universalIdentifier e rimuovi quello vecchio. L’aggiornamento elimina quindi il vecchio provider e ogni connessione effettuata con esso tramite il normale percorso di disconnessione (onDisconnectLogicFunction, revoca del token, pulizia del canale), e i membri si connettono nuovamente tramite il nuovo provider.L’aggiunta o il ricollegamento di una connessione Solo per me richiede l’autorizzazione App utente, mentre l’aggiunta o il ricollegamento di una connessione Condivisa nell’area di lavoro richiede l’autorizzazione App dell’area di lavoro.Usa quella giusta per ciascun handler:scope, dichiara "engines": { "twenty": ">=2.49.0" } nel relativo package.json. Nella stessa versione, il scope di una connessione sostituisce la relativa visibility, che rimane disponibile come alias minuscolo deprecato. listConnections e getConnection di twenty-sdk 2.49.0 leggono scope, pertanto le app sviluppate con esso richiedono un server 2.49.0.Configurazione una tantum del provider
Registra la tua app OAuth presso il servizio di terze parti
Configurazione una tantum del provider
Registra la tua app OAuth presso il servizio di terze parti
- Vai alle impostazioni sviluppatore del provider (ad es. https://linear.app/settings/api/applications/new).
- Imposta la Redirect URI su
\<SERVER_URL>/auth/apps/callback. - Copia il Client ID e il Client Secret generati.
- Apri l’app installata in Twenty come amministratore del server → imposta i valori nelle corrispondenti
serverVariables. - I membri dello spazio di lavoro possono quindi aggiungere connessioni ai provider
WORKSPACEdalla sezione Connessioni dell’app.