Files
composio-skills-reference/composio-sdk/rules/app-connected-accounts.md
sohamganatra b8b711dff6 Add Composio SDK skill with rules and agent config
Adds composio-sdk/ with SKILL.md, AGENTS.md, and 18 rule files
covering Tool Router, direct execution, triggers, and auth patterns.

Source: composiohq/skills

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-05 22:54:21 -08:00

6.3 KiB

title, impact, description, tags
title impact description tags
Connected Accounts Management HIGH Comprehensive guide to CRUD operations on connected accounts with emphasis on secure authentication flows
connected-accounts
authentication
oauth
crud
security

Connected Accounts Management

Using Tool Router? If you're using Tool Router, you can use session.toolkits() to view the auth configs and connected accounts being used by the Tool Router. You only need to use the methods below if you're managing connected accounts outside of Tool Router.

Connected accounts store authentication tokens for external services. Use the connectedAccounts API for CRUD operations.

Create Connected Accounts

Use link() for most flows. Composio handles security, OAuth, and form rendering.

const connectionRequest = await composio.connectedAccounts.link(
  'user_123',
  'auth_config_123',
  { callbackUrl: 'https://your-app.com/callback' }
);

// Redirect user to authentication page
window.location.href = connectionRequest.redirectUrl;

// Wait for completion
const account = await connectionRequest.waitForConnection();

Why use link():

  • Handles OAuth security and form UI
  • Works with 200+ services
  • Whitelabel with your app name/logo (Project Settings on dashboard)
  • No custom UI needed

Advanced: initiate() - Custom Authentication UI

Only use when building custom auth interfaces:

// API Key (custom form)
const connection = await composio.connectedAccounts.initiate(
  'user_123',
  'auth_config_456',
  {
    config: AuthScheme.ApiKey({ api_key: apiKey }),
  }
);

// OAuth with extra params (Zendesk, PostHog, etc.)
const connection = await composio.connectedAccounts.initiate(
  'user_123',
  'zendesk_config',
  {
    config: AuthScheme.OAuth2({ subdomain: "your_subdomain" })
  }
);
window.location.href = connection.redirectUrl;

AuthScheme helpers:

  • AuthScheme.OAuth2({ subdomain: 'example' })
  • AuthScheme.ApiKey({ api_key: 'key123' })
  • AuthScheme.Basic({ username: 'user', password: 'pass' })
  • AuthScheme.BearerToken({ token: 'token123' })

Use initiate() only when:

  • Building custom authentication UI
  • Handling credentials directly in backend
  • OAuth requires extra parameters before redirect

Read Connected Accounts

// List all
const allAccounts = await composio.connectedAccounts.list();

// Filter by user
const userAccounts = await composio.connectedAccounts.list({
  userIds: ['user_123'],
});

// Filter by toolkit
const githubAccounts = await composio.connectedAccounts.list({
  toolkitSlugs: ['github'],
});

// Filter by status
const activeAccounts = await composio.connectedAccounts.list({
  statuses: ['ACTIVE']
});

// Filter by auth config
const configAccounts = await composio.connectedAccounts.list({
  authConfigIds: ['auth_config_123']
});

// Combine filters
const filtered = await composio.connectedAccounts.list({
  userIds: ['user_123'],
  toolkitSlugs: ['github', 'slack'],
  statuses: ['ACTIVE']
});

// Get specific account
const account = await composio.connectedAccounts.get('conn_abc123');

Available filters:

  • userIds - Filter by user IDs
  • toolkitSlugs - Filter by toolkit slugs
  • statuses - Filter by connection statuses (see below for values)
  • authConfigIds - Filter by auth config IDs
  • limit - Results per page
  • cursor - Pagination cursor
  • orderBy - 'created_at' or 'updated_at'

Update Connected Accounts

// Enable/disable
await composio.connectedAccounts.enable('conn_abc123');
await composio.connectedAccounts.disable('conn_abc123');

// Refresh credentials (expired OAuth tokens)
await composio.connectedAccounts.refresh('conn_abc123');

Delete Connected Accounts

await composio.connectedAccounts.delete('conn_abc123');

Warning: Permanent deletion. User must re-authenticate.

Wait for Connection Completion

For async OAuth flows:

// Default timeout (60 seconds)
const account = await composio.connectedAccounts.waitForConnection('conn_123');

// Custom timeout (2 minutes)
const account = await composio.connectedAccounts.waitForConnection('conn_123', 120000);

Errors:

  • ComposioConnectedAccountNotFoundError - Account doesn't exist
  • ConnectionRequestFailedError - Connection failed/expired
  • ConnectionRequestTimeoutError - Timeout exceeded

Common Patterns

OAuth Flow

// Create connection
async function connectUser(userId, authConfigId) {
  const request = await composio.connectedAccounts.link(
    userId,
    authConfigId,
    { callbackUrl: 'https://app.com/callback' }
  );
  return { redirectUrl: request.redirectUrl };
}

// Handle callback
async function handleCallback(connectionId) {
  try {
    const account = await composio.connectedAccounts.waitForConnection(
      connectionId,
      180000
    );
    return { success: true, account };
  } catch (error) {
    if (error.name === 'ConnectionRequestTimeoutError') {
      return { error: 'Timeout. Please try again.' };
    }
    throw error;
  }
}

Check Active Connections

// Filter by status using statuses parameter
async function getUserActiveConnections(userId) {
  const accounts = await composio.connectedAccounts.list({
    userIds: [userId],
    statuses: ['ACTIVE']
  });
  return accounts.items;
}

// Check multiple statuses
async function getUserConnectionsByStatus(userId) {
  const accounts = await composio.connectedAccounts.list({
    userIds: [userId],
    statuses: ['ACTIVE', 'EXPIRED', 'FAILED']
  });
  return accounts.items;
}

async function isToolkitConnected(userId, toolkit) {
  const accounts = await composio.connectedAccounts.list({
    userIds: [userId],
    toolkitSlugs: [toolkit],
    statuses: ['ACTIVE']
  });
  return accounts.items.length > 0;
}

Available statuses:

  • INITIALIZING - Connection being set up
  • INITIATED - Connection initiated, awaiting completion
  • ACTIVE - Connection active and ready to use
  • FAILED - Connection failed
  • EXPIRED - Credentials expired
  • INACTIVE - Connection disabled

Key Points

  • Prefer link() - Security, UI, and whitelabeling handled
  • Store account IDs - Save in your database, associate with users
  • Check status - Verify ACTIVE before use, refresh on errors
  • Handle lifecycle - Disable instead of delete when possible