From 9c18ca433b528302032eedece6ccb881e0ae73fb Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Mon, 6 Apr 2026 11:21:53 -0500 Subject: [PATCH 1/2] fix: pass authConfigs in getConnectors so Composio finds custom OAuth connections Connections created with custom auth configs (TikTok, Instagram) were invisible to getConnectors because it created sessions without matching authConfigs. Composio scopes connection lookups by auth config. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../__tests__/getConnectors.test.ts | 20 +++++++++++++++++++ lib/composio/connectors/getConnectors.ts | 18 +++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/lib/composio/connectors/__tests__/getConnectors.test.ts b/lib/composio/connectors/__tests__/getConnectors.test.ts index 08ec6d06d..cf79321f6 100644 --- a/lib/composio/connectors/__tests__/getConnectors.test.ts +++ b/lib/composio/connectors/__tests__/getConnectors.test.ts @@ -73,6 +73,26 @@ describe("getConnectors", () => { expect(result[0].name).toBe("TikTok"); }); + it("should pass authConfigs when custom OAuth env vars are set", async () => { + process.env.COMPOSIO_TIKTOK_AUTH_CONFIG_ID = "ac_tiktok_123"; + process.env.COMPOSIO_INSTAGRAM_AUTH_CONFIG_ID = "ac_instagram_456"; + + mockToolkits.mockResolvedValue({ items: [] }); + + await getConnectors("account-123"); + + expect(mockComposio.create).toHaveBeenCalledWith("account-123", { + toolkits: ["googlesheets", "googledrive", "googledocs", "tiktok", "instagram"], + authConfigs: { + tiktok: "ac_tiktok_123", + instagram: "ac_instagram_456", + }, + }); + + delete process.env.COMPOSIO_TIKTOK_AUTH_CONFIG_ID; + delete process.env.COMPOSIO_INSTAGRAM_AUTH_CONFIG_ID; + }); + it("should handle inactive connections", async () => { mockToolkits.mockResolvedValue({ items: [ diff --git a/lib/composio/connectors/getConnectors.ts b/lib/composio/connectors/getConnectors.ts index f32312bf3..50ff93397 100644 --- a/lib/composio/connectors/getConnectors.ts +++ b/lib/composio/connectors/getConnectors.ts @@ -28,6 +28,22 @@ export interface GetConnectorsOptions { displayNames?: Record; } +/** + * Build auth configs from environment variables. + * Must match the configs used during authorization so Composio + * can find connections created with custom OAuth credentials. + */ +function buildAuthConfigs(): Record | undefined { + const configs: Record = {}; + if (process.env.COMPOSIO_TIKTOK_AUTH_CONFIG_ID) { + configs.tiktok = process.env.COMPOSIO_TIKTOK_AUTH_CONFIG_ID; + } + if (process.env.COMPOSIO_INSTAGRAM_AUTH_CONFIG_ID) { + configs.instagram = process.env.COMPOSIO_INSTAGRAM_AUTH_CONFIG_ID; + } + return Object.keys(configs).length > 0 ? configs : undefined; +} + /** * Get connectors and their connection status for an account. * @@ -44,8 +60,10 @@ export async function getConnectors( const { displayNames = {} } = options; const composio = await getComposioClient(); + const authConfigs = buildAuthConfigs(); const session = await composio.create(accountId, { toolkits: SUPPORTED_TOOLKITS, + ...(authConfigs && { authConfigs }), }); const toolkits = await session.toolkits(); From f81a7f3eef3e43c2f3937a13f8d744ddf9bb268b Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Mon, 6 Apr 2026 11:30:12 -0500 Subject: [PATCH 2/2] refactor: extract buildAuthConfigs to own file, fix test env cleanup - SRP: moved buildAuthConfigs to lib/composio/connectors/buildAuthConfigs.ts - Fixed test env var cleanup with try/finally to prevent leaking state Co-Authored-By: Claude Opus 4.6 (1M context) --- .../__tests__/getConnectors.test.ts | 33 +++++++++++-------- lib/composio/connectors/buildAuthConfigs.ts | 15 +++++++++ lib/composio/connectors/getConnectors.ts | 17 +--------- 3 files changed, 36 insertions(+), 29 deletions(-) create mode 100644 lib/composio/connectors/buildAuthConfigs.ts diff --git a/lib/composio/connectors/__tests__/getConnectors.test.ts b/lib/composio/connectors/__tests__/getConnectors.test.ts index cf79321f6..688889b9b 100644 --- a/lib/composio/connectors/__tests__/getConnectors.test.ts +++ b/lib/composio/connectors/__tests__/getConnectors.test.ts @@ -74,23 +74,30 @@ describe("getConnectors", () => { }); it("should pass authConfigs when custom OAuth env vars are set", async () => { - process.env.COMPOSIO_TIKTOK_AUTH_CONFIG_ID = "ac_tiktok_123"; - process.env.COMPOSIO_INSTAGRAM_AUTH_CONFIG_ID = "ac_instagram_456"; + const origTiktok = process.env.COMPOSIO_TIKTOK_AUTH_CONFIG_ID; + const origInstagram = process.env.COMPOSIO_INSTAGRAM_AUTH_CONFIG_ID; - mockToolkits.mockResolvedValue({ items: [] }); + try { + process.env.COMPOSIO_TIKTOK_AUTH_CONFIG_ID = "ac_tiktok_123"; + process.env.COMPOSIO_INSTAGRAM_AUTH_CONFIG_ID = "ac_instagram_456"; - await getConnectors("account-123"); + mockToolkits.mockResolvedValue({ items: [] }); - expect(mockComposio.create).toHaveBeenCalledWith("account-123", { - toolkits: ["googlesheets", "googledrive", "googledocs", "tiktok", "instagram"], - authConfigs: { - tiktok: "ac_tiktok_123", - instagram: "ac_instagram_456", - }, - }); + await getConnectors("account-123"); - delete process.env.COMPOSIO_TIKTOK_AUTH_CONFIG_ID; - delete process.env.COMPOSIO_INSTAGRAM_AUTH_CONFIG_ID; + expect(mockComposio.create).toHaveBeenCalledWith("account-123", { + toolkits: ["googlesheets", "googledrive", "googledocs", "tiktok", "instagram"], + authConfigs: { + tiktok: "ac_tiktok_123", + instagram: "ac_instagram_456", + }, + }); + } finally { + if (origTiktok === undefined) delete process.env.COMPOSIO_TIKTOK_AUTH_CONFIG_ID; + else process.env.COMPOSIO_TIKTOK_AUTH_CONFIG_ID = origTiktok; + if (origInstagram === undefined) delete process.env.COMPOSIO_INSTAGRAM_AUTH_CONFIG_ID; + else process.env.COMPOSIO_INSTAGRAM_AUTH_CONFIG_ID = origInstagram; + } }); it("should handle inactive connections", async () => { diff --git a/lib/composio/connectors/buildAuthConfigs.ts b/lib/composio/connectors/buildAuthConfigs.ts new file mode 100644 index 000000000..7bac8d276 --- /dev/null +++ b/lib/composio/connectors/buildAuthConfigs.ts @@ -0,0 +1,15 @@ +/** + * Build auth configs from environment variables. + * Must match the configs used during authorization so Composio + * can find connections created with custom OAuth credentials. + */ +export function buildAuthConfigs(): Record | undefined { + const configs: Record = {}; + if (process.env.COMPOSIO_TIKTOK_AUTH_CONFIG_ID) { + configs.tiktok = process.env.COMPOSIO_TIKTOK_AUTH_CONFIG_ID; + } + if (process.env.COMPOSIO_INSTAGRAM_AUTH_CONFIG_ID) { + configs.instagram = process.env.COMPOSIO_INSTAGRAM_AUTH_CONFIG_ID; + } + return Object.keys(configs).length > 0 ? configs : undefined; +} diff --git a/lib/composio/connectors/getConnectors.ts b/lib/composio/connectors/getConnectors.ts index 50ff93397..243132bf4 100644 --- a/lib/composio/connectors/getConnectors.ts +++ b/lib/composio/connectors/getConnectors.ts @@ -1,4 +1,5 @@ import { getComposioClient } from "../client"; +import { buildAuthConfigs } from "./buildAuthConfigs"; /** * Connector info returned by Composio. @@ -28,22 +29,6 @@ export interface GetConnectorsOptions { displayNames?: Record; } -/** - * Build auth configs from environment variables. - * Must match the configs used during authorization so Composio - * can find connections created with custom OAuth credentials. - */ -function buildAuthConfigs(): Record | undefined { - const configs: Record = {}; - if (process.env.COMPOSIO_TIKTOK_AUTH_CONFIG_ID) { - configs.tiktok = process.env.COMPOSIO_TIKTOK_AUTH_CONFIG_ID; - } - if (process.env.COMPOSIO_INSTAGRAM_AUTH_CONFIG_ID) { - configs.instagram = process.env.COMPOSIO_INSTAGRAM_AUTH_CONFIG_ID; - } - return Object.keys(configs).length > 0 ? configs : undefined; -} - /** * Get connectors and their connection status for an account. *