.agents/features/app-connections.md
App Connections store encrypted authentication credentials (OAuth2 tokens, API keys, basic auth, or custom piece-defined fields) that flow steps use to call external services. They support automatic OAuth2 token refresh with distributed locking, a dual-scope model (project-level or platform-wide), and a "replace" operation that atomically rewires all flow references from one connection to another. The module handles all OAuth2 variants: user-supplied credentials, platform-managed OAuth apps, and Activepieces-hosted cloud OAuth.
packages/server/api/src/app/app-connection/ — backend module (controller, service, entity)packages/shared/src/lib/automation/app-connection/app-connection.ts — core types, enums, and value union typespackages/shared/src/lib/automation/app-connection/dto/upsert-app-connection-request.ts — upsert DTOpackages/shared/src/lib/automation/app-connection/dto/read-app-connection-request.ts — list query DTOpackages/shared/src/lib/automation/app-connection/oauth2-authorization-method.ts — OAuth2 authorization method enumpackages/web/src/features/connections/api/app-connections.ts — frontend API clientpackages/web/src/features/connections/api/global-connections.ts — global (platform-scope) connections API clientpackages/web/src/features/connections/hooks/app-connections-hooks.ts — TanStack Query hooks (appConnectionsQueries, appConnectionsMutations)packages/web/src/features/connections/hooks/global-connections-hooks.ts — global connections hookspackages/web/src/features/connections/utils/oauth2-utils.ts — OAuth2 redirect URL helperspackages/web/src/features/connections/utils/utils.ts — name-uniqueness check helperspackages/web/src/app/routes/connections/index.tsx — project connections list pagepackages/web/src/app/routes/platform/setup/connections/index.tsx — platform-wide global connections pagepackages/web/src/app/connections/new-connection-dialog.tsx — new connection dialog wrapperpackages/web/src/app/connections/create-edit-connection-dialog.tsx — create/edit connection form dialogpackages/web/src/features/connections/components/edit-global-connection-dialog.tsx — edit global connection dialogpackages/web/src/features/connections/components/rename-connection-dialog.tsx — rename connection dialogglobalConnectionsEnabled plan flag.secrets.activepieces.com for token exchange.PROJECT (restricted to projects in projectIds[]) or PLATFORM (available to all projects).OAUTH2, CLOUD_OAUTH2, PLATFORM_OAUTH2, SECRET_TEXT, BASIC_AUTH, CUSTOM_AUTH, NO_AUTH.projectIds for every new project.PLATFORM-scope connection managed from the platform admin UI, shared across all (or selected) projects.AppConnection: id, displayName, externalId, type (AppConnectionType), status (ACTIVE/EXPIRED/ERROR), value (EncryptedObject), platformId, pieceName, pieceVersion, ownerId (nullable FK), projectIds[] (string array — multi-project), scope (PROJECT/PLATFORM), metadata (JSONB), preSelectForNewProjects (boolean).
| Type | Value Fields | Refresh |
|---|---|---|
| OAUTH2 | access_token, refresh_token, client_id, client_secret, token_url, expires_in, claimed_at | Auto-refresh |
| CLOUD_OAUTH2 | Same but tokens exchanged via secrets.activepieces.com | Auto-refresh via cloud |
| PLATFORM_OAUTH2 | Same but uses platform-managed OAuth app credentials | Auto-refresh |
| SECRET_TEXT | token | None |
| BASIC_AUTH | username, password | None |
| CUSTOM_AUTH | piece-defined custom fields | None |
| NO_AUTH | (empty) | None |
projectIds[] array. Query with ArrayContains([projectId]).Automatic on connection retrieval:
decryptAndRefreshConnection() checks if OAuth token expired (15-min early refresh threshold)key = ${projectId}_${externalId}, 60s timeout)refresh() method (different per type: cloud/platform/credentials)POST /v1/app-connections — create/upsert connection (validates via worker EXECUTE_VALIDATION job)POST /v1/app-connections/:id — update displayName, metadata, preSelectForNewProjectsGET /v1/app-connections — list with filters (pieceName, displayName ILIKE, status, scope, externalIds)GET /v1/app-connections/owners — list connection owners (platform admins + project members)POST /v1/app-connections/replace — replace source connection with target across all flowsDELETE /v1/app-connections/:id — hard deletePOST /v1/app-connections/oauth2/authorization-url — generate OAuth redirect URL from piece metadatareplace() atomically updates all flow references (published + draft versions)All connection values encrypted with encryptUtils.encryptObject() (AES-256) before storage, decrypted on retrieval.
The project connections page (/connections) shows a data table with status badges, piece icons, scope indicators, and bulk-delete support. The new-connection-dialog opens create-edit-connection-dialog which renders piece-auth-specific form fields. The "Replace" action opens replace-connections-dialog which calls the replace endpoint. The platform admin global connections page (/platform/setup/connections) uses global-connections-hooks and surfaces edit-global-connection-dialog for managing platform-scope connections and their projectIds assignment. The builder uses connection-select inside step settings to pick or create connections inline.