GenerateSaaS

Integrations

The desktop app's Integrations tab - the same backend-owned connections the web app makes, connected in-app with any provider sign-in opening in the system browser.

The Integrations tab is the desktop screen onto the same backend-owned catalog the web app uses - one catalog, one set of connections, one place they are stored. A user who connects a service in their browser finds it already connected in the app, and the reverse. AI integrations documents the system; this page is what the app adds.

Declared inpackages/config/src/ai/integrations.ts - see Catalog entries
Where users connectSettings > Integrations
What it offersevery catalog entry whose surfaces include desktop
Storedencrypted in your backend database, per user - nothing on the device
Shown whenconfig.ai.enabled, inside the desktop agents envelope

The tab is gated on the AI service, never on how full the catalog is: every input to the tab row is a build fact, so no tab waits on a network read. An empty catalog renders the empty state rather than hiding the tab - it is where a user connects their first integration, so hiding it until they had would be a door that only opens once you are through it.

What the app adds

  • Sign-in opens the system browser. An oauth entry sends the user to the provider in their real browser, so their existing session and password manager work, and the app never handles the credential.
  • No local credential store. There is no keychain entry and no on-device dialog: the app calls the same /ai/integrations routes the web app does, over its device-granted bearer token.
  • Connections follow the workspace, not the device. Each is placed at a scope - a project, an organization, or the connector alone - from the same picker the web app shows, and a second machine inherits whatever that scope makes visible at sign-in. One connection is a tool on every surface at once: web chat, automated runs, and this app's own agents.

How a sign-in reaches the browser

The app authenticates with a bearer token, and a freshly opened system browser carries no session cookie for your API - so it cannot simply open the session-guarded /start URL. The app asks the backend for a start handoff instead: a short-lived, single-use token minted over the channel that is authenticated, then spent by the browser.

The app mints. POST /api/ai/integrations/oauth/{provider}/handoff, authenticated, with the placement it wants: { "scope": "project" | "organization" | "user", "projectId": "..." } (both optional; omitted scope means the connector alone).
The backend authorizes the placement - the deployment's scope ladder, the entry's allowlist, the caller's ownership of the named project - and answers { "startUrl": "...", "expiresInSeconds": 60 }.
The app opens startUrl in the system browser, verbatim. The URL is built server-side, so the app never assembles a path or a parameter name.
The browser is redirected to the provider, consents, and returns to the usual callback, which stores the connection and lands on Settings > Integrations.
PropertyValue
Lifetime60 seconds
Usesone - a replayed link starts nothing
Bound tothe minting user, that one provider, and the placement resolved at mint time
Can it be traded for a session?No. It begins one authorization and does nothing else.

The token stands in for a session in a URL handed to the OS, so it will be written to browser history. That is why it is single-use and expires in a minute - and why the account the tokens land on comes from the server-side record, never from anything the browser sends. A leaked link cannot connect an integration to anyone but the person who minted it.

Local MCP servers are a different feature

An mcp integration is a streamable-HTTP server your backend dials. A stdio server runs on the user's own machine, where no backend can reach it: users add those to their own coding CLI, the app leaves them alone, and they never appear on this tab.

On this page