Fix connector Connect: use the link flow and surface failures

Root cause found by probing the live API: Composio v3 rejects
POST /connected_accounts for Composio-managed OAuth auth configs with a
400 pointing at POST /connected_accounts/link, and the renderer threw
the failure away inside a .then, so clicking Connect did nothing and no
browser opened.

- createConnectedAccount now calls POST /connected_accounts/link with
  auth_config_id and user_id and reads connected_account_id and
  redirect_url; the local mirror records INITIALIZING until the poll
  adopts Composio's real status.
- Connect failures (and a blocked external-URL open) now show as a
  single line on the page instead of vanishing.
This commit is contained in:
ZacharyZhang-NY committed 2026-07-07 01:53:22 -04:00
1 parent a2de132083
commit d19573187c
4 files changed
+40 -16

No files matched your search

@@ -94,19 +94,21 @@ export class ComposioClient {
return id;
}
/** Starts a connection for a user; the redirect URL completes it in the browser. */
/**
* Starts a connection for a user; the redirect URL completes it in the
* browser. Composio-managed auth configs only accept the link flow —
* POST /connected_accounts is rejected for them with a 400.
*/
async createConnectedAccount(input: { authConfigId: string; userId: string }): Promise<{
id: string;
status: string;
redirectUrl: string | null;
}> {
const response = await this.request("POST", `${BASE_URL}/connected_accounts`, {
auth_config: { id: input.authConfigId },
connection: { user_id: input.userId },
const response = await this.request("POST", `${BASE_URL}/connected_accounts/link`, {
auth_config_id: input.authConfigId,
user_id: input.userId,
});
return {
id: String(response.id ?? ""),
status: String(response.status ?? ""),
id: String(response.connected_account_id ?? ""),
redirectUrl: typeof response.redirect_url === "string" ? response.redirect_url : null,
};
}
@@ -26,8 +26,10 @@ export class ComposioConnectionService {
/**
* Starts (or restarts) the company's connection for a toolkit: creates a
* Composio-managed auth config once per toolkit, initiates the connected
* account for the company user, and records the pending account locally.
* The returned redirect URL completes authorization in the browser.
* account for the company user via the link flow, and records the pending
* account locally as INITIALIZING — the poll that follows adopts Composio's
* real status. The returned redirect URL completes authorization in the
* browser.
*/
async connectToolkit(orgId: string, toolkitSlug: string, toolkitName: string): Promise<ConnectComposioToolkitResult> {
const slug = normalizeSlug(toolkitSlug);
@@ -48,8 +50,8 @@ export class ComposioConnectionService {
auth_config_id = excluded.auth_config_id,
status = excluded.status,
updated_at = excluded.updated_at
`).run(account.id, orgId, slug, toolkitName.trim() || slug, authConfigId, account.status || "INITIATED", now, now);
return { accountId: account.id, status: account.status, redirectUrl: account.redirectUrl };
`).run(account.id, orgId, slug, toolkitName.trim() || slug, authConfigId, "INITIALIZING", now, now);
return { accountId: account.id, redirectUrl: account.redirectUrl };
}
/** Pulls account statuses from Composio and updates the local mirror. */