--- title: Conexões description: Permita que seu aplicativo aja em nome de um usuário em serviços de terceiros via OAuth. icon: plug --- Conexões são credenciais que um usuário mantém para um serviço externo (Linear, GitHub, Slack, ...). Seu app declara **como** essas credenciais são obtidas — um **provedor de conexão** — e as consome em tempo de execução para fazer chamadas autenticadas à API de terceiros. Atualmente, apenas o OAuth 2.0 tem suporte. Tipos de credenciais futuros (tokens de acesso pessoal, chaves de API, autenticação básica) serão conectados à mesma interface — apps que já usam `defineConnectionProvider({ type: 'oauth', ... })` não precisarão migrar. Um provedor de conexão descreve o handshake OAuth de que seu app precisa. O usuário clica em "Adicionar conexão" nas configurações do seu app, conclui a tela de consentimento do provedor e uma linha `ConnectedAccount` é criada no seu workspace. Uma configuração funcional precisa de **dois arquivos** — o provedor de conexão e uma declaração correspondente de `serverVariables` em `defineApplication` que contém as credenciais do cliente 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.', defaultRoleUniversalIdentifier: '...', // 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, }, }, }); ``` Pontos-chave: * `name` é a string de identificador exclusivo usada em `listConnections({ providerName })` (kebab-case, deve corresponder a `^[a-z][a-z0-9-]*$`). * `displayName` aparece na aba de configurações do app e na lista de ferramentas de IA. * `clientIdVariable` / `clientSecretVariable` são **nomes**, não valores — devem corresponder às chaves declaradas em `defineApplication.serverVariables`. Os `client_id` e `client_secret` reais são inseridos pelo administrador do servidor por meio da interface de registro do app e nunca são versionados no seu repositório. * Use `serverVariables` (não `applicationVariables`) — as credenciais OAuth são do servidor como um todo e há um app OAuth por servidor do Twenty. * Até que ambos os `serverVariables` sejam preenchidos, a aba de configurações do app mostra uma dica "precisa de administrador do servidor" e o botão "Adicionar conexão" fica desativado. * `type: 'oauth'` é o único valor compatível atualmente. O discriminador é compatível com versões futuras: tipos futuros (`'pat'`, `'api-key'`, ...) adicionarão novos blocos de subconfiguração ao lado de `oauth`. O URL de callback do OAuth que seu provedor precisa adicionar à lista de permissões é: ``` https:///apps/oauth/callback ``` Dentro de um handler de função de lógica, `listConnections({ providerName })` retorna as linhas `ConnectedAccount` deste app para o provedor fornecido, com tokens de acesso atualizados. ```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 }; }; ``` Cada conexão tem: | Campo | Descrição | | ----------------- | -------------------------------------------------------------------------------------------------------------------------- | | `id` | ID de linha exclusivo; passe para `getConnection(id)` para buscar novamente um único registro | | `visibilidade` | `'user'` (privada para um membro do workspace) ou `'workspace'` (compartilhada com todos os membros) | | `escopos` | Permissões OAuth concedidas pelo provedor de origem (distintas de `visibility` — não têm relação) | | `userWorkspaceId` | O id de userWorkspace do proprietário — útil para selecionar "a conexão do usuário da requisição" em gatilhos de rota HTTP | | `accessToken` | Token de acesso OAuth recente (atualizado automaticamente se estiver expirado) | | `name` / `handle` | O nome de exibição da conexão (derivado automaticamente no callback do OAuth, renomeável pelo usuário) | | `authFailedAt` | Definido quando a atualização mais recente falhou; o usuário deve reconectar | Pontos-chave: * Passe `{ providerName }` para filtrar por provedor; omita para obter todas as conexões que este app possui em todos os provedores. * O servidor atualiza transparentemente o token de acesso antes de retornar. Seu handler sempre vê um token utilizável (ou `authFailedAt` definido). * `getConnection(id)` é o equivalente de uma única linha. Quando um usuário clica em "Adicionar conexão", é solicitado que escolha uma visibilidade: * **Apenas para mim** — a credencial é privada para o usuário que a conectou. Qualquer função de lógica chamada em seu nome (gatilho de rota HTTP com `isAuthRequired: true`) a vê; gatilhos cron e eventos de banco de dados não. * **Compartilhada no workspace** — qualquer membro do workspace pode usar a credencial. Gatilhos de cron / banco de dados também a veem, pois não há um usuário da requisição. Use a adequada para cada 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'); ``` Várias conexões por (usuário, provedor) são permitidas, então o mesmo usuário pode manter "Linear pessoal" e "Linear de trabalho" lado a lado. Para cada provedor de conexão, o administrador do servidor precisa primeiro registrar um app OAuth no serviço de terceiros. 1. Acesse as configurações de desenvolvedor do provedor (por exemplo, https://linear.app/settings/api/applications/new). 2. Defina a **URI de redirecionamento** como `\/apps/oauth/callback`. 3. Copie o **ID do cliente** e o **Segredo do cliente** gerados. 4. Abra o app instalado no Twenty como administrador do servidor → defina os valores nos `serverVariables` correspondentes. 5. Os membros do workspace podem então adicionar conexões na seção **Conexões** de cada app.